From a2cd122f78e48ca2bfdbb95a8eccb80a06c2e364 Mon Sep 17 00:00:00 2001 From: dogtopus Date: Thu, 9 Mar 2023 21:43:29 -0400 Subject: [PATCH 001/216] Move FeliCa IDm/PMm display to the new NFC-F info screen The goal is to gradually split out NfcWorkerEventReadFelica into more specific decoders, and have the generic NFC-F info screen display info for tags that don't have a specific decoder, similar to how NFC-A works currently. --- applications/main/nfc/nfc_cli.c | 2 +- .../main/nfc/scenes/nfc_scene_config.h | 2 + .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 80 +++++++++++++++-- .../main/nfc/scenes/nfc_scene_nfcf_menu.c | 80 +++++++++++++++++ .../nfc/scenes/nfc_scene_nfcf_read_success.c | 88 +++++++++++++++++++ applications/main/nfc/scenes/nfc_scene_read.c | 6 +- firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/protocols/felica.c | 8 +- lib/nfc/protocols/felica_util.c | 9 ++ lib/nfc/protocols/felica_util.h | 1 + 10 files changed, 264 insertions(+), 15 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcf_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 0fd8e1e14..12be6ac09 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -45,7 +45,7 @@ static void nfc_cli_detect(Cli* cli, FuriString* args) { for(size_t i = 0; i < 8; i++) { printf("%02X", dev_data.uid[i]); } - printf("\r\nPMm:"); + printf(", PMm:"); for(size_t i = 0; i < 8; i++) { printf("%02X", dev_data.f_data.pmm[i]); } diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a89d6c40b..c896a61ba 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -14,6 +14,8 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) +ADD_SCENE(nfc, nfcf_read_success, NfcfReadSuccess) +ADD_SCENE(nfc, nfcf_menu, NfcfMenu) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 305b57ece..8f8391a64 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { Nfc* nfc = context; @@ -11,6 +12,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { Nfc* nfc = context; Widget* widget = nfc->widget; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + FuriHalNfcType type = nfc_data->type; NfcDeviceData* dev_data = &nfc->dev->dev_data; NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; @@ -40,20 +42,80 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + } else if(protocol == NfcDeviceProtocolFelica) { + furi_string_cat_printf(temp_str, "\e#%s\n", nfc_felica_type(dev_data->felica_data.type)); } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } - // Set tag iso data - char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3'; - furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + // Set tag general data + if(type == FuriHalNfcTypeF) { + // Set NFC-F data + furi_string_cat_printf(temp_str, "ISO 18092 (NFC-F)\n"); + furi_string_cat_printf(temp_str, "CIN:"); + // NFC-F Card Identification Number (CIN) starts at "UID" byte 2. + for(size_t i = 2; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + // The first 2 bytes of the "UID" are Manufacturer Code (MC) + furi_string_cat_printf( + temp_str, + "\nMC: %02X %02X ROM: %02X IC: %02X\n\n", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->f_data.pmm[0], + nfc_data->f_data.pmm[1]); + + furi_string_cat_printf(temp_str, "Timings (1 node/blk):\n"); + furi_string_cat_printf( + temp_str, + "- ReqSvc: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[2], 1)); + furi_string_cat_printf( + temp_str, + "- Fixed: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[3], 0)); + furi_string_cat_printf( + temp_str, + "- Auth1: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[4], 1)); + furi_string_cat_printf( + temp_str, + "- Auth2: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[4], 0)); + furi_string_cat_printf( + temp_str, + "- Read: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[5], 1)); + furi_string_cat_printf( + temp_str, + "- Write: %" PRIuLEAST32 "us\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[6], 1)); + furi_string_cat_printf( + temp_str, + "- Other: %" PRIuLEAST32 "us\n\n", + felica_estimate_timing_us(nfc_data->f_data.pmm[7], 0)); + + furi_string_cat_printf(temp_str, "IDm:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf(temp_str, "\nPMm:"); + for(size_t i = 0; i < sizeof(nfc_data->f_data.pmm); i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->f_data.pmm[i]); + } + } else { // FuriHalNfcTypeA + // Set tag iso data + char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3'; + furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf( + temp_str, "\nATQA: %02X %02X ", nfc_data->a_data.atqa[1], nfc_data->a_data.atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->a_data.sak); } - furi_string_cat_printf( - temp_str, "\nATQA: %02X %02X ", nfc_data->a_data.atqa[1], nfc_data->a_data.atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->a_data.sak); // Set application specific data if(protocol == NfcDeviceProtocolMifareDesfire) { diff --git a/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c new file mode 100644 index 000000000..cae7055b1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcf_menu.c @@ -0,0 +1,80 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + /* + SubmenuIndexSave, + SubmenuIndexEmulate, + */ + SubmenuIndexInfo, +}; + +void nfc_scene_nfcf_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcf_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + // FelicaData* data = &nfc->dev->dev_data.felica_data; + + /* + submenu_add_item( + submenu, "Save IDm", SubmenuIndexSave, nfc_scene_felica_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate IDm", SubmenuIndexEmulate, nfc_scene_felica_menu_submenu_callback, nfc); + */ + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfcf_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcfMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcf_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + /* + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatFelica; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaUnlockMenu); + consumed = true; + } else + */ + if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcfMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfcf_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c new file mode 100644 index 000000000..da695ba83 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcf_read_success.c @@ -0,0 +1,88 @@ +#include "../nfc_i.h" +#include "nfc_device.h" + +void nfc_scene_nfcf_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Nfc* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfcf_read_success_on_enter(void* context) { + Nfc* nfc = context; + + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfcf_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfcf_read_success_widget_callback, nfc); + + FuriString* temp_str = furi_string_alloc(); + + if(dev_data->protocol == NfcDeviceProtocolFelica) { + furi_string_cat_printf(temp_str, "\e#%s", nfc_felica_type(dev_data->felica_data.type)); + } else { + furi_string_cat_printf(temp_str, "\e#Unknown ISO tag"); + } + + furi_string_cat_printf(temp_str, "\nISO 18092 (NFC-F)"); + + furi_string_cat_printf(temp_str, "\nCIN:"); + // NFC-F Card Identification Number (CIN) starts at "UID" byte 2. + for(size_t i = 2; i < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + + // The first 2 bytes of the "UID" are Manufacturer Code (MC) + furi_string_cat_printf( + temp_str, + "\nMC: %02X %02X ROM: %02X IC: %02X", + data->uid[0], + data->uid[1], + data->f_data.pmm[0], + data->f_data.pmm[1]); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfcf_read_success_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcfMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_nfcf_read_success_on_exit(void* context) { + Nfc* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index a4d7be2c3..40645c353 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -57,7 +57,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if((event.event == NfcWorkerEventReadUidNfcB) || - (event.event == NfcWorkerEventReadUidNfcF) || (event.event == NfcWorkerEventReadUidNfcV)) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); @@ -97,6 +96,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } consumed = true; + } else if(event.event == NfcWorkerEventReadUidNfcF) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcfReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; } else if(event.event == NfcWorkerEventReadFelica) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaReadSuccess); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 4da897958..935f0eca8 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.10,, +Version,+,11.13,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -803,6 +803,7 @@ Function,-,fdopen,FILE*,"int, const char*" Function,-,felica_check_ic_type,_Bool,uint8_t* Function,-,felica_clear,void,FelicaData* Function,-,felica_define_normal_block,void,"FelicaService*, uint16_t, uint8_t*" +Function,-,felica_estimate_timing_us,uint_least32_t,"uint_least8_t, uint_least8_t" Function,-,felica_get_ic_type,FelicaICType,uint8_t* Function,-,felica_get_service_name,FuriString*,FelicaService* Function,-,felica_get_system_name,FuriString*,FelicaSystem* diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index d9489cb50..b3405cf6b 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -8,13 +8,15 @@ #define TAG "FeliCa" bool felica_check_ic_type(uint8_t* PMm) { - uint8_t ic_type = PMm[0]; - uint8_t rom_type = PMm[1]; + uint8_t rom_type = PMm[0]; + uint8_t ic_type = PMm[1]; bool is_valid_ic = false; if(ic_type == 0xff) { // RC-S967 in nfc-dep is_valid_ic = true; - } else if(ic_type == 0xf0 || ic_type == 0xf2) { // Lite(S) + } else if(ic_type == 0xf2) { // RC-S732? + is_valid_ic = true; + } else if(ic_type == 0xf0 || ic_type == 0xf1) { // Lite(S) is_valid_ic = true; } else if(ic_type == 0xe1) { // RC-S967 in plug mode is_valid_ic = true; diff --git a/lib/nfc/protocols/felica_util.c b/lib/nfc/protocols/felica_util.c index a5198aa09..aba13c4be 100644 --- a/lib/nfc/protocols/felica_util.c +++ b/lib/nfc/protocols/felica_util.c @@ -1,6 +1,15 @@ #include "./felica.h" #include +static const uint32_t TIME_CONSTANT_US = 302; + +uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units) { + uint_least32_t base_cost_factor = 1 + (timing & 0x7); + uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7); + uint_least32_t scale = 1 << ((timing >> 6) * 2); + return TIME_CONSTANT_US * scale * (base_cost_factor + unit_cost_factor * units); +} + FuriString* felica_get_system_name(FelicaSystem* system) { uint16_t code = system->code; diff --git a/lib/nfc/protocols/felica_util.h b/lib/nfc/protocols/felica_util.h index 4224668eb..e53d66805 100644 --- a/lib/nfc/protocols/felica_util.h +++ b/lib/nfc/protocols/felica_util.h @@ -1,4 +1,5 @@ #include "./felica.h" +uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units); FuriString* felica_get_system_name(FelicaSystem* system); FuriString* felica_get_service_name(FelicaService* service); \ No newline at end of file From 43341980cc2f23535fe53f0b30bd354591ea90f9 Mon Sep 17 00:00:00 2001 From: dogtopus Date: Sat, 18 Mar 2023 03:04:00 -0300 Subject: [PATCH 002/216] Array use refactor Move all arrays to allocating actual data rather than pointers to simplify construction and destruction. Also moved to M_EACH for iterating over arrays for less boilerplate code. Also did some function renaming for extra clarity. root_area is now a node type for simplified area traversal (coming soon). --- .../nfc/scenes/nfc_scene_felica_info_select.c | 87 +++--- .../scenes/nfc_scene_felica_read_success.c | 26 +- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 16 +- .../nfc/scenes/nfc_scene_read_card_type.c | 12 + firmware/targets/f7/api_symbols.csv | 5 +- lib/nfc/nfc_device.h | 1 + lib/nfc/nfc_worker.c | 4 + lib/nfc/protocols/felica.c | 251 +++++++++++------- lib/nfc/protocols/felica.h | 101 +++++-- lib/nfc/protocols/felica_util.c | 1 + 10 files changed, 323 insertions(+), 181 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_felica_info_select.c b/applications/main/nfc/scenes/nfc_scene_felica_info_select.c index 3b7c570d7..7a59521fa 100644 --- a/applications/main/nfc/scenes/nfc_scene_felica_info_select.c +++ b/applications/main/nfc/scenes/nfc_scene_felica_info_select.c @@ -19,24 +19,24 @@ void nfc_scene_felica_info_select_on_enter(void* context) { uint8_t i = 1; if(state->selected_system == NULL || state->selected_system->code == LITE_SYSTEM_CODE) { submenu_set_header(submenu, "Systems"); - FelicaSystemList_it_t it; - for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); - FelicaSystemList_next(it)) { - FelicaSystem* current_system = *FelicaSystemList_ref(it); - FuriString* system_name = felica_get_system_name(current_system); - submenu_add_item( - submenu, - furi_string_get_cstr(system_name), - i++, - nfc_scene_felica_info_select_submenu_callback, - nfc); - furi_string_free(system_name); - } + for + M_EACH(current_system, data->systems, FelicaSystemArray_t) { + FuriString* system_name = felica_get_system_name(current_system); + submenu_add_item( + submenu, + furi_string_get_cstr(system_name), + i++, + nfc_scene_felica_info_select_submenu_callback, + nfc); + furi_string_free(system_name); + } } else { FelicaSystem* system = state->selected_system; FuriString* header = furi_string_alloc_printf("%04X/", system->code); - FelicaArea* area = &system->root_area; + FelicaNode* root = &system->root; + furi_assert(root->type == FelicaNodeTypeArea); + FelicaArea* area = root->area; if(FelicaAreaPath_size(state->selected_areas) > 0) { FelicaAreaPath_it_t it; for(FelicaAreaPath_it(it, state->selected_areas); !FelicaAreaPath_end_p(it); @@ -51,32 +51,30 @@ void nfc_scene_felica_info_select_on_enter(void* context) { submenu_set_header(submenu, furi_string_get_cstr(header)); furi_string_free(header); - FelicaNodeList_it_t it; - for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); - FelicaNodeList_next(it)) { - FelicaNode* node = *FelicaNodeList_ref(it); - FuriString* node_name = furi_string_alloc(); - if(node->type == FelicaNodeTypeArea) { - furi_string_printf(node_name, "Area %d", node->area->number); - submenu_add_item( - submenu, - furi_string_get_cstr(node_name), - i++, - nfc_scene_felica_info_select_submenu_callback, - nfc); - } else { - uint16_t service_code = node->service->number << 6; - furi_string_printf(node_name, "Service %04X", service_code); - submenu_add_item( - submenu, - furi_string_get_cstr(node_name), - i++, - nfc_scene_felica_info_select_submenu_callback, - nfc); - } + for + M_EACH(node, area->nodes, FelicaNodeArray_t) { + FuriString* node_name = furi_string_alloc(); + if(node->type == FelicaNodeTypeArea) { + furi_string_printf(node_name, "Area %d", node->area->number); + submenu_add_item( + submenu, + furi_string_get_cstr(node_name), + i++, + nfc_scene_felica_info_select_submenu_callback, + nfc); + } else { + uint16_t service_code = node->service->number << 6; + furi_string_printf(node_name, "Service %04X", service_code); + submenu_add_item( + submenu, + furi_string_get_cstr(node_name), + i++, + nfc_scene_felica_info_select_submenu_callback, + nfc); + } - furi_string_free(node_name); - } + furi_string_free(node_name); + } } state->selected_service = NULL; @@ -102,7 +100,7 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even index -= 1; if(state->selected_system == NULL) { - state->selected_system = *FelicaSystemList_get(data->systems, index); + state->selected_system = FelicaSystemArray_get(data->systems, index); if(state->selected_system->code == LITE_SYSTEM_CODE) { scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaServiceData); } else { @@ -111,12 +109,15 @@ bool nfc_scene_felica_info_select_on_event(void* context, SceneManagerEvent even consumed = true; } else { FelicaNode* selected_node = NULL; + + FelicaNode* root = &(state->selected_system->root); + furi_assert(root->type == FelicaNodeTypeArea); + if(FelicaAreaPath_size(state->selected_areas) == 0) { - selected_node = - *FelicaNodeList_get(state->selected_system->root_area.nodes, index); + selected_node = FelicaNodeArray_get(root->area->nodes, index); } else { FelicaArea* current_area = *FelicaAreaPath_back(state->selected_areas); - selected_node = *FelicaNodeList_get(current_area->nodes, index); + selected_node = FelicaNodeArray_get(current_area->nodes, index); } if(selected_node->type == FelicaNodeTypeArea) { diff --git a/applications/main/nfc/scenes/nfc_scene_felica_read_success.c b/applications/main/nfc/scenes/nfc_scene_felica_read_success.c index 52bba0ee3..79dd82297 100644 --- a/applications/main/nfc/scenes/nfc_scene_felica_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_felica_read_success.c @@ -29,21 +29,19 @@ void nfc_scene_felica_read_success_on_enter(void* context) { } else { temp_str = furi_string_alloc_printf("\e#%s", nfc_felica_type(felica_data->type)); - FelicaSystemList_it_t it; - for(FelicaSystemList_it(it, felica_data->systems); !FelicaSystemList_end_p(it); - FelicaSystemList_next(it)) { - FelicaSystem* current_system = *FelicaSystemList_ref(it); - furi_string_cat_printf( - temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number); - furi_string_cat_printf(temp_str, "\nIDm:\n "); - for(size_t i = 0; i < 8; i++) { - furi_string_cat_printf(temp_str, "%02X", current_system->idm[i]); + for + M_EACH(current_system, felica_data->systems, FelicaSystemArray_t) { + furi_string_cat_printf( + temp_str, "\nSystem %04X (#%d):", current_system->code, current_system->number); + furi_string_cat_printf(temp_str, "\nIDm:\n "); + for(size_t i = 0; i < 8; i++) { + furi_string_cat_printf(temp_str, "%02X", current_system->idm[i]); + } + furi_string_cat_printf(temp_str, "\nPMm:\n "); + for(size_t i = 0; i < 8; i++) { + furi_string_cat_printf(temp_str, "%02X", current_system->pmm[i]); + } } - furi_string_cat_printf(temp_str, "\nPMm:\n "); - for(size_t i = 0; i < 8; i++) { - furi_string_cat_printf(temp_str, "%02X", current_system->pmm[i]); - } - } } widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 8f8391a64..26f9c4eb3 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -66,35 +66,35 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { nfc_data->f_data.pmm[0], nfc_data->f_data.pmm[1]); - furi_string_cat_printf(temp_str, "Timings (1 node/blk):\n"); + furi_string_cat_printf(temp_str, "MRT (1 node/blk):\n"); furi_string_cat_printf( temp_str, "- ReqSvc: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[2], 1)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_VARIABLE_MRT], 1)); furi_string_cat_printf( temp_str, "- Fixed: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[3], 0)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_FIXED_MRT], 0)); furi_string_cat_printf( temp_str, "- Auth1: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[4], 1)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_MUTUAL_AUTH_MRT], 1)); furi_string_cat_printf( temp_str, "- Auth2: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[4], 0)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_MUTUAL_AUTH_MRT], 0)); furi_string_cat_printf( temp_str, "- Read: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[5], 1)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_READ_MRT], 1)); furi_string_cat_printf( temp_str, "- Write: %" PRIuLEAST32 "us\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[6], 1)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_WRITE_MRT], 1)); furi_string_cat_printf( temp_str, "- Other: %" PRIuLEAST32 "us\n\n", - felica_estimate_timing_us(nfc_data->f_data.pmm[7], 0)); + felica_estimate_timing_us(nfc_data->f_data.pmm[FELICA_PMM_OTHER_MRT], 0)); furi_string_cat_printf(temp_str, "IDm:"); for(size_t i = 0; i < nfc_data->uid_len; i++) { diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 865b3f54b..ed33515d4 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -8,6 +8,7 @@ enum SubmenuIndex { SubmenuIndexReadEMV, SubmenuIndexReadNFCA, SubmenuIndexReadFelica, + SubmenuIndexReadNFCF, }; void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { @@ -56,6 +57,12 @@ void nfc_scene_read_card_type_on_enter(void* context) { SubmenuIndexReadFelica, nfc_scene_read_card_type_submenu_callback, nfc); + submenu_add_item( + submenu, + "Read NFC-F data", + SubmenuIndexReadNFCF, + nfc_scene_read_card_type_submenu_callback, + nfc); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType); submenu_set_selected_item(submenu, state); @@ -97,6 +104,11 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } + if(event.event == SubmenuIndexReadNFCF) { + nfc->dev->dev_data.read_mode = NfcReadModeNFCF; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event); } return consumed; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 935f0eca8..fb5603041 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.13,, +Version,+,11.14,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -808,14 +808,15 @@ Function,-,felica_get_ic_type,FelicaICType,uint8_t* Function,-,felica_get_service_name,FuriString*,FelicaService* Function,-,felica_get_system_name,FuriString*,FelicaSystem* Function,-,felica_lite_can_read_without_mac,_Bool,"uint8_t*, uint8_t" +Function,-,felica_lite_dump_data,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*" Function,-,felica_lite_prepare_unencrypted_read,uint8_t,"uint8_t*, const FelicaReader*, _Bool, const uint8_t*, uint8_t" Function,-,felica_lite_prepare_unencrypted_write,uint8_t,"uint8_t*, const FelicaReader*, const uint8_t*, uint8_t, const uint8_t*" Function,-,felica_parse_unencrypted_read,uint16_t,"uint8_t*, uint8_t, FelicaReader*, uint8_t*, uint16_t" Function,-,felica_parse_unencrypted_write,_Bool,"uint8_t*, uint8_t, FelicaReader*" Function,-,felica_prepare_unencrypted_read,uint8_t,"uint8_t*, const FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t" Function,-,felica_prepare_unencrypted_write,uint8_t,"uint8_t*, FelicaReader*, const uint16_t*, uint8_t, const uint32_t*, uint8_t, const uint8_t*" +Function,-,felica_push_normal_block,void,"FelicaService*, uint8_t*" Function,-,felica_read_card,_Bool,"FuriHalNfcTxRxContext*, FelicaData*, uint8_t*, uint8_t*" -Function,-,felica_read_lite_system,_Bool,"FuriHalNfcTxRxContext*, FelicaReader*, FelicaData*, FelicaSystem*" Function,-,feof,int,FILE* Function,-,feof_unlocked,int,FILE* Function,-,ferror,int,FILE* diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index fc0e5bfbc..3edd01070 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -63,6 +63,7 @@ typedef enum { NfcReadModeEMV, NfcReadModeNFCA, NfcReadModeFelica, + NfcReadModeNFCF, } NfcReadMode; typedef struct { diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index b034dd202..96cab9f5b 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -508,6 +508,10 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { break; } } + } else if(read_mode == NfcReadModeNFCF) { + nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + event = NfcWorkerEventReadUidNfcF; + break; } } } else { diff --git a/lib/nfc/protocols/felica.c b/lib/nfc/protocols/felica.c index b3405cf6b..827187564 100644 --- a/lib/nfc/protocols/felica.c +++ b/lib/nfc/protocols/felica.c @@ -151,6 +151,55 @@ FelicaICType felica_get_ic_type(uint8_t* PMm) { return FelicaICType2K; } +/** Parse common FeliCa response headers. + * + * This parses and validates the most commonly occurring response header types. + * + * The header needs to match the (length, res, idm) format, and also (sf1, sf2) when always_succeed + * is set to false. + * + * @param buf RX buffer. + * @param len RX buffer length. + * @param reader The FeliCa reader context. + * @param expected_resp Expected response code. Must be an odd number. + * @param always_succeed When set to true, skip status flags (sf1 and sf2) parsing. + * @return The number of bytes parsed, or 0 when response is invalid or status flags are set. + */ +static uint8_t felica_consume_header( + uint8_t* buf, + uint8_t len, + FelicaReader* reader, + uint8_t expected_resp, + bool always_succeed) { + furi_assert(expected_resp & 1); + furi_assert(buf != NULL); + furi_assert(reader != NULL); + + uint8_t header_size = always_succeed ? 10 : 12; + if(len < header_size) { + FURI_LOG_E(TAG, "Malformed header: too short."); + return 0; + } + if(buf[1] != expected_resp) { + FURI_LOG_E(TAG, "Expecting %u, got %u.", expected_resp, buf[1]); + return 0; + } + if(memcmp(&buf[2], reader->current_idm, 8) != 0) { + FURI_LOG_E(TAG, "IDm mismatch."); + return 0; + } + if(always_succeed) { + reader->status_flags[0] = buf[10]; + reader->status_flags[1] = buf[11]; + if(reader->status_flags[0] != 0 || reader->status_flags[1] != 0) { + FURI_LOG_W( + TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]); + return 0; + } + } + return header_size; +} + uint8_t felica_prepare_unencrypted_read( uint8_t* dest, const FelicaReader* reader, @@ -212,32 +261,12 @@ uint16_t felica_parse_unencrypted_read( FelicaReader* reader, uint8_t* out, uint16_t out_len) { - if(len < 12) { - return false; - } - len--; - buf++; - - if(*buf != FELICA_UNENCRYPTED_READ_RES) { - return false; - } - len--; - buf++; - - if(memcmp(buf, reader->current_idm, 8) != 0) { - return false; - } - len -= 8; - buf += 8; - - reader->status_flags[0] = buf[0]; - reader->status_flags[1] = buf[1]; - len -= 2; - buf += 2; - if(reader->status_flags[0] != 0) { - FURI_LOG_W(TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]); + uint8_t consumed = felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_READ_RES, false); + if(!consumed) { return 0; } + len -= consumed; + buf += consumed; if(len < 1) { return 0; @@ -315,48 +344,77 @@ uint8_t felica_lite_prepare_unencrypted_write( } bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* reader) { - if(len < 12) { + uint8_t consumed = + felica_consume_header(buf, len, reader, FELICA_UNENCRYPTED_WRITE_RES, false); + if(!consumed) { return false; } + return true; +} + +uint8_t felica_prepare_request_system_code(uint8_t* dest, FelicaReader* reader) { + dest[0] = FELICA_REQUEST_SYSTEM_CODE_CMD; + memcpy(&dest[1], reader->current_idm, 8); + return 9; +} + +bool felica_parse_request_system_code( + uint8_t* buf, + uint8_t len, + FelicaReader* reader, + FelicaSystemArray_t* systems) { + uint8_t consumed = + felica_consume_header(buf, len, reader, FELICA_REQUEST_SYSTEM_CODE_RES, true); + if(consumed == 0) { + return false; + } + len -= consumed; + buf += consumed; + + uint8_t entries = *buf; len--; buf++; - if(*buf != FELICA_UNENCRYPTED_WRITE_RES) { + if(len < 2 * entries) { + FURI_LOG_E(TAG, "FELICA_REQUEST_SYSTEM_CODE_RES: Response too short"); return false; } - len--; - buf++; - if(memcmp(buf, reader->current_idm, 8) != 0) { - return false; - } - len -= 8; - buf += 8; + for(uint8_t idx = 0; idx < entries; idx++) { + FelicaSystem* system = FelicaSystemArray_push_new(*systems); + furi_assert(system != NULL); - reader->status_flags[0] = buf[0]; - reader->status_flags[1] = buf[1]; - len -= 2; - buf += 2; - if(reader->status_flags[0] != 0) { - FURI_LOG_W(TAG, "SF1: %02X SF2: %02X", reader->status_flags[0], reader->status_flags[1]); - return 0; + // Set system code + system->number = idx; + system->code = buf[2 * idx] | (buf[2 * idx + 1] << 8); + + FURI_LOG_D(TAG, "Found system code %04X", system->code); + + // Fill in IDm and PMm + memcpy(system->idm, reader->current_idm, 8); + memcpy(system->pmm, reader->current_pmm, 8); + + // Set system index field in IDm + system->idm[0] &= 0x0f; + system->idm[0] |= ((idx & 0xf) << 4); } return true; } -void felica_parse_system_info(FelicaSystem* system, uint8_t* IDm, uint8_t* PMm) { - memcpy(system->idm, IDm, 8); - memcpy(system->pmm, PMm, 8); - for(int i = 0; i < 6; i++) { - char MRT_byte = PMm[2 + i]; - FelicaMRTParts* mrt_data = &system->maximum_response_times[i]; - mrt_data->real_a = (MRT_byte & 7) + 1; - MRT_byte >>= 3; - mrt_data->real_b = (MRT_byte & 7) + 1; - MRT_byte >>= 3; - mrt_data->exponent = (MRT_byte & 3); - } +static FelicaSystem* felica_gen_monolithic_system_code( + FelicaReader* reader, + FelicaSystemArray_t* systems, + uint16_t system_code) { + FelicaSystem* system = FelicaSystemArray_push_new(*systems); + furi_assert(reader != NULL); + furi_assert(system != NULL); + + memcpy(system->idm, reader->current_idm, 8); + memcpy(system->pmm, reader->current_pmm, 8); + system->code = system_code; + + return system; } bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number) { @@ -368,12 +426,16 @@ bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number) } void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data) { - FelicaBlock* block = malloc(sizeof(FelicaBlock)); + FelicaBlock* block = FelicaBlockArray_safe_get(service->blocks, number); memcpy(block->data, data, FELICA_BLOCK_SIZE); - FelicaBlockList_set_at(service->blocks, number, block); } -bool felica_read_lite_system( +void felica_push_normal_block(FelicaService* service, uint8_t* data) { + FelicaBlock* block = FelicaBlockArray_push_new(service->blocks); + memcpy(block->data, data, FELICA_BLOCK_SIZE); +} + +bool felica_lite_dump_data( FuriHalNfcTxRxContext* tx_rx, FelicaReader* reader, FelicaData* data, @@ -425,8 +487,6 @@ bool felica_read_lite_system( return false; } - system->code = LITE_SYSTEM_CODE; - FelicaLiteInfo* lite_info = &system->lite_info; lite_info->card_key_1 = NULL; lite_info->card_key_2 = NULL; @@ -568,6 +628,22 @@ bool felica_read_lite_system( return true; } +bool felica_std_request_system_code( + FuriHalNfcTxRxContext* tx_rx, + FelicaReader* reader, + FelicaSystemArray_t* systems) { + tx_rx->tx_bits = 8 * felica_prepare_request_system_code(tx_rx->tx_data, reader); + if(!furi_hal_nfc_tx_rx_full(tx_rx)) { + FURI_LOG_E(TAG, "Bad exchange requesting system code"); + return false; + } + if(!felica_parse_request_system_code(tx_rx->rx_data, tx_rx->rx_bits / 8, reader, systems)) { + FURI_LOG_E(TAG, "Bad response to Request System Code command"); + return false; + } + return true; +} + bool felica_read_card( FuriHalNfcTxRxContext* tx_rx, FelicaData* data, @@ -583,31 +659,24 @@ bool felica_read_card( memcpy(reader.current_idm, polled_idm, 8); memcpy(reader.current_pmm, polled_pmm, 8); - FelicaSystem* current_system = malloc(sizeof(FelicaSystem)); - FelicaSystemList_init(data->systems); - FelicaSystemList_push_back(data->systems, current_system); - - felica_parse_system_info(current_system, polled_idm, polled_pmm); + FelicaSystemArray_init(data->systems); if(data->type == FelicaICTypeLite || data->type == FelicaICTypeLiteS) { FURI_LOG_I(TAG, "Reading Felica Lite system"); - felica_read_lite_system(tx_rx, &reader, data, current_system); + FelicaSystem* lite_system = + felica_gen_monolithic_system_code(&reader, &(data->systems), LITE_SYSTEM_CODE); + felica_lite_dump_data(tx_rx, &reader, data, lite_system); card_read = true; break; } + FURI_LOG_I(TAG, "Reading Felica Standard system"); } while(false); return card_read; } void felica_service_clear(FelicaService* service) { - FelicaBlockList_it_t it; - for(FelicaBlockList_it(it, service->blocks); !FelicaBlockList_end_p(it); - FelicaBlockList_next(it)) { - FelicaBlock* block = *FelicaBlockList_ref(it); - free(block); - } - FelicaBlockList_clear(service->blocks); + FelicaBlockArray_clear(service->blocks); } void felica_lite_clear(FelicaLiteInfo* lite_info) { @@ -630,31 +699,33 @@ void felica_lite_clear(FelicaLiteInfo* lite_info) { } } +void felica_node_clear(FelicaNode* node); + void felica_area_clear(FelicaArea* area) { - FelicaNodeList_it_t it; - for(FelicaNodeList_it(it, area->nodes); !FelicaNodeList_end_p(it); FelicaNodeList_next(it)) { - FelicaNode* node = *FelicaNodeList_ref(it); - if(node->type == FelicaNodeTypeArea) { - felica_area_clear(node->area); - } else if(node->type == FelicaNodeTypeService) { - felica_service_clear(node->service); + for + M_EACH(node, area->nodes, FelicaNodeArray_t) { + felica_node_clear(node); } - free(node); + FelicaNodeArray_clear(area->nodes); +} + +void felica_node_clear(FelicaNode* node) { + if(node->type == FelicaNodeTypeArea) { + felica_area_clear(node->area); + } else if(node->type == FelicaNodeTypeService) { + felica_service_clear(node->service); } - FelicaNodeList_clear(area->nodes); } void felica_clear(FelicaData* data) { - FelicaSystemList_it_t it; - for(FelicaSystemList_it(it, data->systems); !FelicaSystemList_end_p(it); - FelicaSystemList_next(it)) { - FelicaSystem* system = *FelicaSystemList_ref(it); - if(system->code == LITE_SYSTEM_CODE) { - felica_lite_clear(&system->lite_info); - ; - } else { - felica_area_clear(&system->root_area); + for + M_EACH(system, data->systems, FelicaSystemArray_t) { + if(system->code == LITE_SYSTEM_CODE) { + felica_lite_clear(&system->lite_info); + } else { + felica_node_clear(&system->root); + FelicaPublicServiceDict_clear(system->public_services); + } } - } - FelicaSystemList_clear(data->systems); + FelicaSystemArray_clear(data->systems); } \ No newline at end of file diff --git a/lib/nfc/protocols/felica.h b/lib/nfc/protocols/felica.h index fa81cba2f..21bd5532c 100644 --- a/lib/nfc/protocols/felica.h +++ b/lib/nfc/protocols/felica.h @@ -10,6 +10,8 @@ #define MRT_T_SIG_x16 4833038.24 //ns, MRT_T_SIG * (4 ** 2) #define MRT_T_SIG_x64 19332152.96 //ns, MRT_T_SIG * (4 ** 2) +#define FELICA_PMM_MRT_BASE 2 + #define FELICA_VARIABLE_MRT 0 #define FELICA_FIXED_MRT 1 #define FELICA_MUTUAL_AUTH_MRT 2 @@ -17,6 +19,13 @@ #define FELICA_WRITE_MRT 4 #define FELICA_OTHER_MRT 5 +#define FELICA_PMM_VARIABLE_MRT (FELICA_PMM_MRT_BASE + FELICA_VARIABLE_MRT) +#define FELICA_PMM_FIXED_MRT (FELICA_PMM_MRT_BASE + FELICA_FIXED_MRT) +#define FELICA_PMM_MUTUAL_AUTH_MRT (FELICA_PMM_MRT_BASE + FELICA_MUTUAL_AUTH_MRT) +#define FELICA_PMM_READ_MRT (FELICA_PMM_MRT_BASE + FELICA_READ_MRT) +#define FELICA_PMM_WRITE_MRT (FELICA_PMM_MRT_BASE + FELICA_WRITE_MRT) +#define FELICA_PMM_OTHER_MRT (FELICA_PMM_MRT_BASE + FELICA_OTHER_MRT) + #define FELICA_BLOCK_SIZE 16 #define CYBERNET_SYSTEM_CODE 0x0003 @@ -55,9 +64,13 @@ #define FELICA_UNENCRYPTED_READ_CMD 0x06 #define FELICA_UNENCRYPTED_WRITE_CMD 0x08 +#define FELICA_SEARCH_SERVICE_CODE_CMD 0x0a +#define FELICA_REQUEST_SYSTEM_CODE_CMD 0x0c #define FELICA_UNENCRYPTED_READ_RES 0x07 #define FELICA_UNENCRYPTED_WRITE_RES 0x09 +#define FELICA_SEARCH_SERVICE_CODE_RES 0x0b +#define FELICA_REQUEST_SYSTEM_CODE_RES 0x0d typedef enum { FelicaICTypeRC_SA24_10K, // RC-SA24/1x @@ -88,13 +101,6 @@ typedef enum { FelicaICTypeSuica, // https://www.tuv-nederland.nl/assets/files/cerfiticaten/2019/07/cr-nscib-cc-10-30076-cr.pdf } FelicaICType; -typedef struct { - uint8_t exponent : 2; - // Incremented at read - uint8_t real_a : 4; - uint8_t real_b : 4; -} FelicaMRTParts; - typedef enum { FelicaServiceTypeRandom = (0b0010 << 2), FelicaServiceTypeCyclic = (0b0011 << 2), @@ -121,20 +127,22 @@ DICT_SET_DEF( FelicaServiceAttribute, M_ENUM_OPLIST(FelicaServiceAttribute, FelicaServiceAttributeAuthRW)) -typedef FelicaMRTParts FelicaMRTParameters[6]; - typedef struct { uint8_t data[FELICA_BLOCK_SIZE]; } FelicaBlock; -ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST) +// TODO properly remove this +//ARRAY_DEF(FelicaBlockList, FelicaBlock*, M_PTR_OPLIST) +ARRAY_DEF(FelicaBlockArray, FelicaBlock, M_POD_OPLIST) +#define M_OPL_FelicaBlockArray_t() ARRAY_OPLIST(FelicaBlockArray, M_POD_OPLIST) typedef struct { uint16_t number; FelicaServiceAttributeList_t access_control_list; // accounts for overlap services - bool is_extended_overlap; + bool is_extended_overlap; // We don't know much about this currently. will always be false union { - FelicaBlockList_t blocks; + // TODO change this to use FelicaBlockArray_t + FelicaBlockArray_t blocks; struct { uint16_t overlap_target; uint8_t block_start; @@ -149,23 +157,44 @@ typedef enum { } FelicaNodeType; struct _FelicaArea_t; -typedef struct { +typedef struct _FelicaArea_t FelicaArea; + +struct _FelicaNode_s; +typedef struct _FelicaNode_s FelicaNode; + +struct _FelicaNode_s { + /** Node type. */ FelicaNodeType type; + /** Borrowed pointer to its parent node. */ + FelicaNode* parent; union { - struct _FelicaArea_t* area; + /** (Area/dir type only) The area struct. */ + FelicaArea* area; + /** (Service/file type only) The service struct. */ FelicaService* service; }; -} FelicaNode; +}; -ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST) +// TODO properly remove this +//ARRAY_DEF(FelicaNodeList, FelicaNode*, M_PTR_OPLIST) +ARRAY_DEF(FelicaNodeArray, FelicaNode, M_POD_OPLIST) +#define M_OPL_FelicaNodeArray_t() ARRAY_OPLIST(FelicaNodeArray, M_POD_OPLIST) -typedef struct _FelicaArea_t { +ARRAY_DEF(FelicaNodeRefArray, FelicaNode*, M_PTR_OPLIST) +#define M_OPL_FelicaNodeRefArray_t() ARRAY_OPLIST(FelicaNodeRefArray, M_PTR_OPLIST) + +// { service_number: service_ptr_in_tree } +DICT_DEF2(FelicaPublicServiceDict, uint16_t, M_DEFAULT_OPLIST, FelicaService*, M_PTR_OPLIST) +#define M_OPL_FelicaPublicServiceDict_t() \ + DICT_OPLIST(FelicaPublicServiceDict, M_DEFAULT_OPLIST, M_PTR_OPLIST) + +struct _FelicaArea_t { uint16_t number; bool can_create_subareas; uint16_t end_service_code; - FelicaNodeList_t nodes; -} FelicaArea; + FelicaNodeArray_t nodes; +}; typedef struct { uint8_t* S_PAD[14]; @@ -186,24 +215,39 @@ typedef struct { } FelicaLiteInfo; typedef struct _FelicaSystem_t { + /** FeliCa system index. */ uint8_t number; + /** If the system belongs to a FeliCa Lite (and be its only system). */ + bool is_lite; + /** FeliCa system code. */ uint16_t code; + /** System IDm with system index bitfield properly set. */ uint8_t idm[8]; + /** Cached card PMm. */ uint8_t pmm[8]; - FelicaMRTParameters maximum_response_times; union { + /** (For FeliCa Lite only) Card content. */ FelicaLiteInfo lite_info; - FelicaArea root_area; + struct { + /** (For FeliCa Standard only) The root of the raw filesystem tree. */ + FelicaNode root; + /** (For FeliCa Standard only) Shortcut for all publicly accessible services for quick + * access by card parsers. */ + FelicaPublicServiceDict_t public_services; + }; }; } FelicaSystem; -ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST) +// TODO properly remove this +//ARRAY_DEF(FelicaSystemList, FelicaSystem*, M_PTR_OPLIST) +ARRAY_DEF(FelicaSystemArray, FelicaSystem, M_POD_OPLIST) +#define M_OPL_FelicaSystemArray_t() ARRAY_OPLIST(FelicaSystemArray, M_POD_OPLIST) typedef struct { FelicaICType type; uint8_t subtype; - FelicaSystemList_t systems; + FelicaSystemArray_t systems; } FelicaData; typedef struct { @@ -255,8 +299,17 @@ bool felica_parse_unencrypted_write(uint8_t* buf, uint8_t len, FelicaReader* rea bool felica_lite_can_read_without_mac(uint8_t* mc_r_restr, uint8_t block_number); void felica_define_normal_block(FelicaService* service, uint16_t number, uint8_t* data); +void felica_push_normal_block(FelicaService* service, uint8_t* data); -bool felica_read_lite_system( +/** Dump a FeliCa Lite or Lite-S tag. + * + * @param tx_rx NFC context. + * @param reader FeliCa reader context. + * @param data Output data object. + * @param system FeliCa system description. + * @return true if successful. + */ +bool felica_lite_dump_data( FuriHalNfcTxRxContext* tx_rx, FelicaReader* reader, FelicaData* data, diff --git a/lib/nfc/protocols/felica_util.c b/lib/nfc/protocols/felica_util.c index aba13c4be..481ea5ed7 100644 --- a/lib/nfc/protocols/felica_util.c +++ b/lib/nfc/protocols/felica_util.c @@ -3,6 +3,7 @@ static const uint32_t TIME_CONSTANT_US = 302; +// TODO move this to felica.c uint_least32_t felica_estimate_timing_us(uint_least8_t timing, uint_least8_t units) { uint_least32_t base_cost_factor = 1 + (timing & 0x7); uint_least32_t unit_cost_factor = 1 + ((timing >> 3) & 0x7); From 887884faa1438d718736637923ce10cc9251eccb Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 10 Apr 2023 02:20:51 +0100 Subject: [PATCH 003/216] Fix release script artifacts --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db717f6f2..1c4c39f8f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,8 +69,8 @@ jobs: draft: false prerelease: false files: | - dist/${{ env.ARTIFACT_TGZ }} - dist/${{ env.ARTIFACT_ZIP }} + ${{ env.ARTIFACT_TGZ }} + ${{ env.ARTIFACT_ZIP }} name: "${{ env.VERSION_TAG }}" tag_name: "${{ env.VERSION_TAG }}" target_commitish: ${{ github.event.pull_request.base.ref }} From 48cc9f46af35e07d729752c1fbc8fd9ebbe8ee77 Mon Sep 17 00:00:00 2001 From: Clara K Date: Tue, 11 Apr 2023 17:56:33 +0200 Subject: [PATCH 004/216] correctly crediting nano for his work, not a clown that stole code --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index c9773fdbc..87e6df32e 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -123,7 +123,7 @@ Note: This repo is always updated with OFW & Unleashed. No need to mention all t - Custom subghz presets - Multiple NFC protocols - Multiple Sub-Ghz protocols | Merged from Unleashed, thanks @xMasterX -- Subghz and IR signal replication via gpio | Credits to @ankris812 +- Subghz and IR signal replication via gpio | Credits to @xMasterX - New API Routes for Locale settings ``` From 22482232556f218414f17fee09747ab4f4a394d1 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 22 Apr 2023 09:06:33 +0100 Subject: [PATCH 005/216] Workflow updates --- .github/workflow_data/discord.py | 45 +++++++++++++++++++++++++++++--- .github/workflows/discord.yml | 4 +-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/.github/workflow_data/discord.py b/.github/workflow_data/discord.py index 17659f8f7..2b9e29da9 100644 --- a/.github/workflow_data/discord.py +++ b/.github/workflow_data/discord.py @@ -9,7 +9,7 @@ if __name__ == "__main__": with open(os.environ["GITHUB_EVENT_PATH"], "r") as f: event = json.load(f) - webhook = "DEV_DISCORD_WEBHOOK" + webhook = "DEV_WEBHOOK" title = desc = url = "" color = 0 fields = [] @@ -45,7 +45,7 @@ if __name__ == "__main__": title = f"Pull Request {event['action'].title()} ({branch}): {name}" match event["action"]: case "opened": - desc = (event["body"][:2045] + "...") if len(event["body"]) > 2048 else event["body"] + desc = (pr["body"][:2045] + "...") if len(pr["body"]) > 2048 else pr["body"] color = 3669797 fields.append( @@ -80,7 +80,7 @@ if __name__ == "__main__": case "release": match event["action"]: case "published": - webhook = "DEV_DISCORD_WEBHOOK" + webhook = "RELEASE_WEBHOOK" color = 13845998 title = f"New Release published: {event['name']}" desc += f"Changelog:" @@ -123,6 +123,45 @@ if __name__ == "__main__": case _: sys.exit(1) + case "workflow_run": + run = event["workflow_run"] + url = run["html_url"] + title = "Workflow " + match run["conclusion"]: + case "action_required": + title += "Requires Attention" + color = 16751872 + case "failure": + title += "Failed" + color = 16723712 + case _: + sys.exit(0) + title += f": {run['name']}" + + case "issues": + issue = event["issue"] + url = issue["html_url"] + name = issue["title"][:50] + ("..." if len(issue["title"]) > 50 else "") + title = f"Issue {event['action'].title()}: {name}" + match event["action"]: + case "opened": + desc = (issue["body"][:2045] + "...") if len(issue["body"]) > 2048 else issue["body"] + color = 3669797 + case "closed": + color = 16723712 + case "reopened": + color = 16751872 + case _: + sys.exit(1) + + case "issue_comment": + comment = event["comment"] + issue = event["issue"] + url = comment["html_url"] + title = f"New Comment on Issue: {issue['title']}" + color = 3669797 + desc = (comment["body"][:2045] + "...") if len(comment["body"]) > 2048 else comment["body"] + case _: sys.exit(1) diff --git a/.github/workflows/discord.yml b/.github/workflows/discord.yml index 8ff4775ac..840f01d67 100644 --- a/.github/workflows/discord.yml +++ b/.github/workflows/discord.yml @@ -10,7 +10,7 @@ on: release: types: - "published" - check_suite: + workflow_run: types: - "completed" issues: @@ -32,5 +32,5 @@ jobs: - name: Send webhook env: - DEV_DISCORD_WEBHOOK: "https://discord.com/api/webhooks/${{ secrets.DEV_WEBHOOK_ID }}/${{ secrets.DEV_WEBHOOK_TOKEN }}" + DEV_WEBHOOK: "https://discord.com/api/webhooks/${{ secrets.DEV_WEBHOOK_ID }}/${{ secrets.DEV_WEBHOOK_TOKEN }}" run: python .github/workflow_data/discord.py From 85f482fe24f9a3be6d085587dd70498e1ffa7271 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 22 Apr 2023 09:25:53 +0100 Subject: [PATCH 006/216] Cleanup workflows --- .github/workflow_data/{discord.py => webhook.py} | 0 .github/workflows/build.yml | 4 ++-- .github/workflows/hotfix.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 2 +- .../workflows/{sonarqube.yaml => sonarcloud.yaml} | 4 ++-- .../{check_submodules.yml => submodules.yml} | 4 ++-- .github/workflows/{discord.yml => webhook.yml} | 12 ++++++++++-- 8 files changed, 19 insertions(+), 11 deletions(-) rename .github/workflow_data/{discord.py => webhook.py} (100%) rename .github/workflows/{sonarqube.yaml => sonarcloud.yaml} (98%) rename .github/workflows/{check_submodules.yml => submodules.yml} (96%) rename .github/workflows/{discord.yml => webhook.yml} (73%) diff --git a/.github/workflow_data/discord.py b/.github/workflow_data/webhook.py similarity index 100% rename from .github/workflow_data/discord.py rename to .github/workflow_data/webhook.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 715070b83..37ec991e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: 'Build artifact' +name: 'Build' on: push: @@ -41,7 +41,7 @@ jobs: with: name: updater path: | - dist/${{ env.DEFAULT_TARGET }}-* + dist/${{ env.DEFAULT_TARGET }}-*/${{ env.DEFAULT_TARGET }}-update-*/ # - name: 'Find Previous Comment' # if: ${{ github.event.pull_request }} diff --git a/.github/workflows/hotfix.yml b/.github/workflows/hotfix.yml index 82fb6fa30..505f9c676 100644 --- a/.github/workflows/hotfix.yml +++ b/.github/workflows/hotfix.yml @@ -1,4 +1,4 @@ -name: "Hotfix integration" +name: "Hotfix" on: pull_request_review: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 818aa7d84..da9ca2a87 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: 'Lint formatting' +name: 'Lint' on: push: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1c4c39f8f..61bc01fcf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: "Release integration" +name: 'Release' on: pull_request_review: diff --git a/.github/workflows/sonarqube.yaml b/.github/workflows/sonarcloud.yaml similarity index 98% rename from .github/workflows/sonarqube.yaml rename to .github/workflows/sonarcloud.yaml index 7f3d311b0..e763aaad7 100644 --- a/.github/workflows/sonarqube.yaml +++ b/.github/workflows/sonarcloud.yaml @@ -1,4 +1,4 @@ -name: 'SonarCloud analysis' +name: 'SonarCloud' on: workflow_dispatch: @@ -10,7 +10,7 @@ env: DEFAULT_TARGET: f7 jobs: - analyze: + sonarcloud: runs-on: ubuntu-latest env: SONAR_SCANNER_VERSION: 4.7.0.2747 diff --git a/.github/workflows/check_submodules.yml b/.github/workflows/submodules.yml similarity index 96% rename from .github/workflows/check_submodules.yml rename to .github/workflows/submodules.yml index ad63f711b..52342fd04 100644 --- a/.github/workflows/check_submodules.yml +++ b/.github/workflows/submodules.yml @@ -1,4 +1,4 @@ -name: 'Check submodules' +name: 'Submodules' on: push: @@ -10,7 +10,7 @@ on: pull_request: jobs: - check_protobuf: + submodules: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/discord.yml b/.github/workflows/webhook.yml similarity index 73% rename from .github/workflows/discord.yml rename to .github/workflows/webhook.yml index 840f01d67..c3f4d9432 100644 --- a/.github/workflows/discord.yml +++ b/.github/workflows/webhook.yml @@ -1,4 +1,4 @@ -name: Discord webhook +name: 'Webhook' on: push: @@ -11,6 +11,14 @@ on: types: - "published" workflow_run: + workflows: + - "Build" + - "Hotfix" + - "Lint" + - "Release" + - "SonarCloud" + - "Submodules" + - "Webhook" types: - "completed" issues: @@ -33,4 +41,4 @@ jobs: - name: Send webhook env: DEV_WEBHOOK: "https://discord.com/api/webhooks/${{ secrets.DEV_WEBHOOK_ID }}/${{ secrets.DEV_WEBHOOK_TOKEN }}" - run: python .github/workflow_data/discord.py + run: python .github/workflow_data/webhook.py From b1d916d87f3aed6e762603bf81b7bdfb239edf83 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 22 Apr 2023 09:26:37 +0100 Subject: [PATCH 007/216] Fix webhook workflow --- .github/workflows/webhook.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/webhook.yml b/.github/workflows/webhook.yml index c3f4d9432..a4e380467 100644 --- a/.github/workflows/webhook.yml +++ b/.github/workflows/webhook.yml @@ -18,7 +18,6 @@ on: - "Release" - "SonarCloud" - "Submodules" - - "Webhook" types: - "completed" issues: From 64453a0b727eb42468ffd8bb695a48a10a640842 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Apr 2023 17:57:08 +0100 Subject: [PATCH 008/216] Dev webhook fixes --- .github/workflow_data/webhook.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflow_data/webhook.py b/.github/workflow_data/webhook.py index 2b9e29da9..ee97e254b 100644 --- a/.github/workflow_data/webhook.py +++ b/.github/workflow_data/webhook.py @@ -24,12 +24,13 @@ if __name__ == "__main__": else f"{count} New Commit{'' if count == 1 else 's'}" ) desc = f"[**{change}**]({event['compare']}) | [{branch}]({event['repository']['html_url']}/tree/{branch})\n" - for commit in event["commits"][:10]: - msg = commit['message'].splitlines()[0] + for i, commit in enumerate(event["commits"]): + msg = commit['message'].splitlines()[0].replace("`", "") msg = msg[:50] + ("..." if len(msg) > 50 else "") desc += f"\n[`{commit['id'][:7]}`]({commit['url']}): {msg} - [__{commit['author']['username']}__](https://github.com/{commit['author']['username']})" - if count > 10: - desc += f"\n+ {count - 10} more commits" + if len(desc) > 2020: + desc = desc.rsplit("\n", 1)[0] + f"\n+ {count - i} more commits" + break url = event["compare"] color = 16723712 if event["forced"] else 3669797 From 4298aaab02b31ddcd2be7809cfacb6f72ed38ccd Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:40:10 +0100 Subject: [PATCH 009/216] Fix PR webhook --- .github/workflow_data/webhook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflow_data/webhook.py b/.github/workflow_data/webhook.py index ee97e254b..08eab46fb 100644 --- a/.github/workflow_data/webhook.py +++ b/.github/workflow_data/webhook.py @@ -39,7 +39,7 @@ if __name__ == "__main__": url = pr["html_url"] branch = pr["base"]["ref"] + ( "" - if pr["base"]["full_name"] != pr["head"]["full_name"] + if pr["base"]["repo"]["full_name"] != pr["head"]["repo"]["full_name"] else f" <- {pr['head']['ref']}" ) name = pr["title"][:50] + ("..." if len(pr["title"]) > 50 else "") From 512fe8aeada2d38194518e44765e1404d00b5f27 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 30 Apr 2023 14:59:38 +0300 Subject: [PATCH 010/216] Fix readme --- ReadMe.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReadMe.md b/ReadMe.md index 7ba70bc33..1611bed67 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -161,6 +161,7 @@ You can support us by using links or addresses below: - **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main) - **ProtoView** [(by antirez)](https://github.com/antirez/protoview) - **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) +- IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407) Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/) From 3846e811579ed0586ba641a5e5863747d715f760 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Thu, 1 Dec 2022 01:37:50 +0100 Subject: [PATCH 011/216] added DigitalSequence to chain multiple DigitalSignals added PulseReader for hardware assisted digital signal sampling --- lib/SConscript | 1 + lib/digital_signal/digital_signal.c | 451 +++++++++++++++++++++++----- lib/digital_signal/digital_signal.h | 43 ++- lib/pulse_reader/pulse_reader.c | 202 +++++++++++++ lib/pulse_reader/pulse_reader.h | 140 +++++++++ 5 files changed, 761 insertions(+), 76 deletions(-) create mode 100644 lib/pulse_reader/pulse_reader.c create mode 100644 lib/pulse_reader/pulse_reader.h diff --git a/lib/SConscript b/lib/SConscript index f5d4689f1..51f6f7544 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -4,6 +4,7 @@ env.Append( LINT_SOURCES=[ Dir("app-scened-template"), Dir("digital_signal"), + Dir("pulse_reader"), Dir("drivers"), Dir("flipper_format"), Dir("infrared"), diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 46ca307a7..c7e8bbca5 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -1,23 +1,46 @@ #include "digital_signal.h" #include -#include -#include +#include #include -#pragma GCC optimize("O3,unroll-loops,Ofast") +#define TAG "DigitalSignal" + + +#define F_TIM (64000000.0) +#define T_TIM 1562 /* 15.625 ns *100 */ +#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ -#define F_TIM (64000000.0) -#define T_TIM 1562 //15.625 ns *100 -#define T_TIM_DIV2 781 //15.625 ns / 2 *100 DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { DigitalSignal* signal = malloc(sizeof(DigitalSignal)); signal->start_level = true; signal->edges_max_cnt = max_edges_cnt; - signal->edge_timings = malloc(max_edges_cnt * sizeof(uint32_t)); - signal->reload_reg_buff = malloc(max_edges_cnt * sizeof(uint32_t)); + signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->edge_cnt = 0; + signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); + signal->reload_reg_entries = 0; + signal->reload_reg_remainder = 0; + + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_gpio.NbData = 2; + signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->ARR); + signal->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -37,7 +60,10 @@ bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) { if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) { return false; } - + /* in case there are no edges in our target signal, the signal to append makes the rules */ + if(!signal_a->edge_cnt) { + signal_a->start_level = signal_b->start_level; + } bool end_level = signal_a->start_level; if(signal_a->edge_cnt) { end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2); @@ -72,6 +98,32 @@ uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) { return signal->edge_cnt; } +void digital_signal_add(DigitalSignal* signal, uint32_t ticks) { + furi_assert(signal); + furi_assert(signal->edge_cnt < signal->edges_max_cnt); + + signal->edge_timings[signal->edge_cnt++] = ticks; +} + +void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level) { + furi_assert(signal); + furi_assert(signal->edge_cnt < signal->edges_max_cnt); + + /* virgin signal? add it as the only level */ + if(signal->edge_cnt == 0) { + signal->start_level = level; + signal->edge_timings[signal->edge_cnt++] = ticks; + } else { + bool end_level = signal->start_level ^ !(signal->edge_cnt % 2); + + if(level != end_level) { + signal->edge_timings[signal->edge_cnt++] = ticks; + } else { + signal->edge_timings[signal->edge_cnt - 1] += ticks; + } + } +} + uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { furi_assert(signal); furi_assert(edge_num < signal->edge_cnt); @@ -79,76 +131,76 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { return signal->edge_timings[edge_num]; } -void digital_signal_prepare_arr(DigitalSignal* signal) { - uint32_t t_signal_rest = signal->edge_timings[0]; - uint32_t r_count_tick_arr = 0; - uint32_t r_rest_div = 0; +void digital_signal_prepare(DigitalSignal* signal) { + furi_assert(signal); + furi_assert(signal->gpio); + furi_assert(signal->gpio->pin); + + /* set up signal polarities */ + uint32_t bit_set = signal->gpio->pin; + uint32_t bit_reset = signal->gpio->pin << 16; - for(size_t i = 0; i < signal->edge_cnt - 1; i++) { - r_count_tick_arr = t_signal_rest / T_TIM; - r_rest_div = t_signal_rest % T_TIM; - t_signal_rest = signal->edge_timings[i + 1] + r_rest_div; + if(signal->start_level) { + signal->gpio_buff[0] = bit_set; + signal->gpio_buff[1] = bit_reset; + } else { + signal->gpio_buff[0] = bit_reset; + signal->gpio_buff[1] = bit_set; + } - if(r_rest_div < T_TIM_DIV2) { - signal->reload_reg_buff[i] = r_count_tick_arr - 1; - } else { - signal->reload_reg_buff[i] = r_count_tick_arr; - t_signal_rest -= T_TIM; + /* set up edge timings */ + signal->reload_reg_entries = 0; + + for(size_t pos = 0; pos < signal->edge_cnt; pos++) { + uint32_t pulse_duration = signal->edge_timings[pos] + signal->reload_reg_remainder; + uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; + signal->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); + + if(pulse_ticks > 1) { + signal->reload_reg_buff[signal->reload_reg_entries++] = pulse_ticks - 1; } } } -void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { +static void digital_signal_stop_dma() { + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); +} + +static void digital_signal_stop_timer() { + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); +} + +static bool digital_signal_setup_dma(DigitalSignal* signal) { furi_assert(signal); - furi_assert(gpio); - // Configure gpio as output - furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - - // Init gpio buffer and DMA channel - uint16_t gpio_reg = gpio->port->ODR; - uint16_t gpio_buff[2]; - if(signal->start_level) { - gpio_buff[0] = gpio_reg | gpio->pin; - gpio_buff[1] = gpio_reg & ~(gpio->pin); - } else { - gpio_buff[0] = gpio_reg & ~(gpio->pin); - gpio_buff[1] = gpio_reg | gpio->pin; + if(!signal->reload_reg_entries) { + return false; } - LL_DMA_InitTypeDef dma_config = {}; - dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR); - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_CIRCULAR; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; - dma_config.NbData = 2; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); - // Init timer arr register buffer and DMA channel - digital_signal_prepare_arr(signal); - dma_config.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_NORMAL; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.NbData = signal->edge_cnt - 2; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config.Priority = LL_DMA_PRIORITY_HIGH; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff; + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->BSRR); + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; + signal->dma_config_timer.NbData = signal->reload_reg_entries; + + /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer); + + /* enable both DMA channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - // Set up timer + return true; +} + +static void digital_signal_setup_timer() { + + digital_signal_stop_timer(); + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); @@ -156,18 +208,267 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableUpdateEvent(TIM2); LL_TIM_EnableDMAReq_UPDATE(TIM2); +} - // Start transactions - LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it? +static void digital_signal_start_timer() { + LL_TIM_GenerateEvent_UPDATE(TIM2); LL_TIM_EnableCounter(TIM2); +} - while(!LL_DMA_IsActiveFlag_TC2(DMA1)) - ; +void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { + furi_assert(signal); + + if(!signal->edge_cnt) { + return; + } + + /* Configure gpio as output */ + signal->gpio = gpio; + furi_hal_gpio_init(signal->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + /* single signal, add a temporary, terminating edge at the end */ + signal->edge_timings[signal->edge_cnt++] = 10; + digital_signal_prepare(signal); + + digital_signal_setup_dma(signal); + digital_signal_setup_timer(); + digital_signal_start_timer(); + + while(!LL_DMA_IsActiveFlag_TC2(DMA1)) { + } + + digital_signal_stop_timer(); + digital_signal_stop_dma(); + + signal->edge_cnt--; +} + +void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { + sequence->signals_size = size; + sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); + sequence->signals_prolonged = malloc(sequence->signals_size * sizeof(bool)); +} + +void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { + sequence->sequence_used = 0; + sequence->sequence_size = size; + sequence->sequence = malloc(sequence->sequence_size); +} + +DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { + + DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); + + sequence->gpio = gpio; + sequence->bake = false; + + digital_sequence_alloc_signals(sequence, 32); + digital_sequence_alloc_sequence(sequence, size); + + return sequence; +} + +void digital_sequence_free(DigitalSequence* sequence) { + furi_assert(sequence); + + free(sequence->signals); + free(sequence->sequence); + free(sequence); +} + +void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index, DigitalSignal* signal) { + furi_assert(sequence); + furi_assert(signal); + furi_assert(signal_index < sequence->signals_size); + + sequence->signals[signal_index] = signal; + signal->gpio = sequence->gpio; + signal->reload_reg_remainder = 0; + + digital_signal_prepare(signal); +} + +void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { + furi_assert(sequence); + furi_assert(signal_index < sequence->signals_size); + + if(sequence->sequence_used >= sequence->sequence_size) { + sequence->sequence_size += 256; + sequence->sequence = realloc(sequence->sequence, sequence->sequence_size); + } + + sequence->sequence[sequence->sequence_used++] = signal_index; +} + +void digital_signal_update_dma(DigitalSignal* signal) { + + volatile uint32_t dma1_data[] = { + /* R6 */ (uint32_t)&(DMA1_Channel1->CCR), + /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, + /* R8 */ 2, + /* R9 */ (uint32_t)&(signal->gpio->port->BSRR), + /* R10 */ (uint32_t)signal->gpio_buff, + /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN }; + + volatile uint32_t dma2_data[] = { + /* R0 */ (uint32_t)&(DMA1_Channel2->CCR), + /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, + /* R2 */ (uint32_t)signal->reload_reg_entries, + /* R3 */ (uint32_t)&(TIM2->ARR), + /* R4 */ (uint32_t)signal->reload_reg_buff, + /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN }; + + + /* hurry when setting up next transfer */ + asm volatile("\t" + "MOV r6, %[data1]\n\t" + "MOV r7, %[data2]\n\t" + + "PUSH {r0-r12}\n\t" + + "LDM r7, {r0-r5}\n\t" + "LDM r6, {r6-r11}\n\t" + + "loop:\n\t" + "LDR r12, [r0, #4]\n\t" + "CMP r12, #0\n\t" + "BNE loop\n\t" + + "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ + "STR r11, [r6, #0]\n\t" /* enable channel again */ + "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ + "STR r5, [r0, #0]\n\t" /* enable channel again */ + + "POP {r0-r12}\n\t" + + : /* no outputs*/ + : /* inputs */ + [data1] "r" (dma1_data), + [data2] "r" (dma2_data) + : "r6", "r7" ); + LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC2(DMA1); - LL_TIM_DisableCounter(TIM2); - LL_TIM_SetCounter(TIM2, 0); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); +} + +static bool digital_sequence_send_signal(DigitalSignal* signal) { + furi_assert(signal); + + /* the first iteration has to set up the whole machinery */ + if(!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) { + if(!digital_signal_setup_dma(signal)) { + FURI_LOG_D(TAG, "digital_sequence_send_signal: Signal has no entries, aborting"); + return false; + } + digital_signal_setup_timer(); + digital_signal_start_timer(); + } else { + /* configure next polarities and timings */ + digital_signal_update_dma(signal); + } + + return true; +} + +DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { + + uint32_t edges = 0; + + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { + uint8_t signal_index = sequence->sequence[pos]; + DigitalSignal *sig = sequence->signals[signal_index]; + + edges += sig->edge_cnt; + } + + DigitalSignal* ret = digital_signal_alloc(edges); + + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { + uint8_t signal_index = sequence->sequence[pos]; + DigitalSignal *sig = sequence->signals[signal_index]; + + digital_signal_append(ret, sig); + } + + return ret; +} + +bool digital_sequence_send(DigitalSequence* sequence) { + furi_assert(sequence); + + furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + if(sequence->bake) { + DigitalSignal* sig = digital_sequence_bake(sequence); + + digital_signal_send(sig, sequence->gpio); + digital_signal_free(sig); + return true; + } + + int32_t remainder = 0; + FURI_CRITICAL_ENTER(); + + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { + uint8_t signal_index = sequence->sequence[pos]; + DigitalSignal *sig = sequence->signals[signal_index]; + + if(!sig) { + FURI_LOG_D(TAG, "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", signal_index, pos); + break; + } + + /* when we are too late more than half a tick, make the first edge temporarily longer */ + bool needs_prolongation = false; + + if(remainder >= T_TIM_DIV2) { + remainder -= T_TIM; + needs_prolongation = true; + } + + /* update the total remainder */ + remainder += sig->reload_reg_remainder; + + /* do we need to update the prolongation? */ + if(needs_prolongation != sequence->signals_prolonged[signal_index]) { + if(needs_prolongation) { + sig->edge_timings[0]++; + } else { + sig->edge_timings[0]--; + } + sequence->signals_prolonged[signal_index] = needs_prolongation; + } + + bool success = digital_sequence_send_signal(sig); + + if(!success) { + break; + } + } + FURI_CRITICAL_EXIT(); + + while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { + } + + digital_signal_stop_timer(); + digital_signal_stop_dma(); + + /* undo previously prolonged edges */ + for(uint32_t pos = 0; pos < sequence->signals_size; pos++) { + DigitalSignal *sig = sequence->signals[pos]; + + if(sig && sequence->signals_prolonged[pos]) { + sig->edge_timings[0]--; + sequence->signals_prolonged[pos] = false; + } + } + + return true; +} + +void digital_sequence_clear(DigitalSequence* sequence) { + furi_assert(sequence); + + sequence->sequence_used = 0; } diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 90905d74b..8f6142258 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -5,26 +5,57 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { #endif +/* helper for easier signal generation */ +#define DIGITAL_SIGNAL_MS(x) (x*100000000UL) +#define DIGITAL_SIGNAL_US(x) (x*100000UL) +#define DIGITAL_SIGNAL_NS(x) (x*100UL) +#define DIGITAL_SIGNAL_PS(x) (x/10UL) + + typedef struct { bool start_level; uint32_t edge_cnt; uint32_t edges_max_cnt; uint32_t* edge_timings; uint32_t* reload_reg_buff; + uint32_t reload_reg_entries; + uint32_t reload_reg_remainder; + uint32_t gpio_buff[2]; + const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; } DigitalSignal; +typedef struct { + uint8_t signals_size; + bool bake; + uint32_t sequence_used; + uint32_t sequence_size; + DigitalSignal** signals; + bool* signals_prolonged; + uint8_t* sequence; + const GpioPin* gpio; +} DigitalSequence; + + DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); void digital_signal_free(DigitalSignal* signal); +void digital_signal_add(DigitalSignal* signal, uint32_t ticks); + +void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level); + bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b); -void digital_signal_prepare_arr(DigitalSignal* signal); +void digital_signal_prepare(DigitalSignal* signal); bool digital_signal_get_start_level(DigitalSignal* signal); @@ -34,6 +65,16 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); + +DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio); +void digital_sequence_free(DigitalSequence* sequence); +void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index, DigitalSignal* signal); +void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index); +bool digital_sequence_send(DigitalSequence* sequence); +void digital_sequence_clear(DigitalSequence* sequence); + + + #ifdef __cplusplus } #endif diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c new file mode 100644 index 000000000..18e7ee98d --- /dev/null +++ b/lib/pulse_reader/pulse_reader.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include + +#include "pulse_reader.h" + + +#define GPIO_PIN_MAP(pin, prefix) \ + (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ + ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ + ((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \ + ((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \ + ((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \ + ((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \ + ((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \ + ((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \ + ((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \ + ((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \ + ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ + ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ + ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ + ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ + ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ + prefix##15) + +#define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE) + + + +PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { + + PulseReader* signal = malloc(sizeof(PulseReader)); + signal->timer_buffer = malloc(size * sizeof(uint32_t)); + signal->gpio_buffer = malloc(size * sizeof(uint32_t)); + signal->dma_channel = LL_DMA_CHANNEL_4; + signal->gpio = gpio; + signal->size = size; + signal->timer_value = 0; + signal->pos = 0; + + pulse_reader_set_timebase(signal, PulseReaderUnit64MHz); + pulse_reader_set_bittime(signal, 1); + + signal->dma_config_timer.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT); + signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t) signal->timer_buffer; + signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_timer.Priority = LL_DMA_PRIORITY_VERYHIGH; + + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + return signal; +} + +void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit) { + switch(unit) { + case PulseReaderUnit64MHz: + signal->unit_multiplier = 1; + signal->unit_divider = 1; + break; + case PulseReaderUnitPicosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1; + break; + case PulseReaderUnitNanosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000; + break; + case PulseReaderUnitMicrosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000000; + break; + } +} + +void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) { + signal->bit_time = bit_time; +} + +void pulse_reader_free(PulseReader* signal) { + free(signal->timer_buffer); + free(signal->gpio_buffer); + free(signal); +} + +uint32_t pulse_reader_samples(PulseReader* signal) { + uint32_t dma_pos = signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); + + return ((signal->pos + signal->size) - dma_pos) % signal->size; +} + +void pulse_reader_stop(PulseReader* signal) { + LL_DMA_DisableChannel(DMA1, signal->dma_channel); + LL_DMA_DisableChannel(DMA1, signal->dma_channel+1); + LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); + LL_TIM_DisableCounter(TIM2); +} + +void pulse_reader_start(PulseReader* signal) { + /* configure DMA to read from a timer peripheral */ + signal->dma_config_timer.NbData = signal->size; + + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->IDR); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buffer; + signal->dma_config_gpio.NbData = signal->size; + + /* start counter */ + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetPrescaler(TIM2, 0); + LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); + + /* generator 0 gets fed by EXTI_LINEn */ + LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); + /* trigger on rising edge of the interrupt */ + LL_DMAMUX_SetRequestGenPolarity(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING); + /* now enable request generation again */ + LL_DMAMUX_EnableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); + + /* we need the EXTI to be configured as interrupt generating line, but no ISR registered */ + furi_hal_gpio_init_ex(signal->gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + + /* capture current timer */ + signal->pos = 0; + signal->start_level = furi_hal_gpio_read(signal->gpio); + signal->timer_value = TIM2->CNT; + signal->gpio_mask = signal->gpio->pin; + + /* now set up DMA with these settings */ + LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer); + LL_DMA_Init(DMA1, signal->dma_channel + 1, &signal->dma_config_gpio); + LL_DMA_EnableChannel(DMA1, signal->dma_channel); + LL_DMA_EnableChannel(DMA1, signal->dma_channel + 1); +} + +uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { + + uint32_t start_time = DWT->CYCCNT; + uint32_t timeout_ticks = timeout_us * (F_TIM2/1000000); + + do { + /* get the DMA's next write position by reading "remaining length" register */ + uint32_t dma_pos = signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); + + /* the DMA has advanced in the ringbuffer */ + if(dma_pos != signal->pos) { + + uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value; + uint32_t last_gpio_value = signal->gpio_value; + + signal->gpio_value = signal->gpio_buffer[signal->pos]; + + /* check if the GPIO really toggled. if not, we lost an edge :( */ + if(((last_gpio_value ^ signal->gpio_value) & signal->gpio_mask) != signal->gpio_mask) { + signal->gpio_value ^= signal->gpio_mask; + return PULSE_READER_LOST_EDGE; + } + signal->timer_value = signal->timer_buffer[signal->pos]; + + signal->pos++; + signal->pos %= signal->size; + + uint32_t delta_unit = 0; + + /* probably larger values, so choose a wider data type */ + if(signal->unit_divider > 1) { + delta_unit = (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider); + } else { + delta_unit = delta * signal->unit_multiplier; + } + + /* if to be scaled to bit times, save a few instructions. should be faster */ + if(signal->bit_time > 1) { + return (delta_unit + signal->bit_time / 2) / signal->bit_time; + } + + return delta_unit; + } + + /* check for timeout */ + uint32_t elapsed = DWT->CYCCNT - start_time; + + if(elapsed > timeout_ticks) { + return PULSE_READER_NO_EDGE; + } + } while(true); +} diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h new file mode 100644 index 000000000..f55a65931 --- /dev/null +++ b/lib/pulse_reader/pulse_reader.h @@ -0,0 +1,140 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL +#define PULSE_READER_LOST_EDGE 0xFFFFFFFEUL +#define F_TIM2 64000000UL + +/** + * unit of the edge durations to return + */ +typedef enum { + PulseReaderUnit64MHz, + PulseReaderUnitPicosecond, + PulseReaderUnitNanosecond, + PulseReaderUnitMicrosecond, +} PulseReaderUnit; + + +typedef struct { + bool start_level; + uint32_t* timer_buffer; + uint32_t* gpio_buffer; + uint32_t size; + uint32_t pos; + uint32_t timer_value; + uint32_t gpio_value; + uint32_t gpio_mask; + uint32_t unit_multiplier; + uint32_t unit_divider; + uint32_t bit_time; + uint32_t dma_channel; + const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_timer; + LL_DMA_InitTypeDef dma_config_gpio; +} PulseReader; + + +/** Allocate a PulseReader object + * + * Allocates memory for a ringbuffer and initalizes the object + * + * @param[in] gpio the GPIO to use. will get configured as input. + * @param[in] size number of edges to buffer + */ +PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size); + + +/** Free a PulseReader object + * + * Frees all memory of the given object + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_free(PulseReader* signal); + + +/** Start signal capturing + * + * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_start(PulseReader* signal); + + +/** Stop signal capturing + * + * Frees DMA1, TIM2 and DMAMUX_REQ_GEN_0 + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_stop(PulseReader* signal); + + +/** Recevie a sample from ringbuffer + * + * Waits for the specified time until a new edge gets detected. + * If not configured otherwise, the pulse duration will be in picosecond resolution. + * If a bittime was configured, the return value will contain the properly rounded + * number of bit times measured. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] timeout_us time to wait for a signal [µs] + * + * @returns the scaled value of the pulse duration + */ +uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us); + + +/** Get available samples + * + * Get the number of available samples in the ringbuffer + * + * @param[in] signal previously allocated PulseReader object. + * + * @returns the number of samples in buffer + */ +uint32_t pulse_reader_samples(PulseReader* signal); + + +/** Set timebase + * + * Set the timebase to be used when returning pulse duration. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] unit PulseReaderUnit64MHz or PulseReaderUnitPicosecond + */ +void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit); + + +/** Set bit time + * + * Set the number of timebase units per bit. + * When set, the pulse_reader_receive() will return an already rounded + * bit count value instead of the raw duration. + * + * Set to 1 to return duration again. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] bit_time + */ +void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time); + + +#ifdef __cplusplus +} +#endif From 26c4e886777e23d39218102d695a43f99d30aaa9 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Thu, 1 Dec 2022 18:43:22 +0100 Subject: [PATCH 012/216] added send_time option to start a signal at a specific DWT->CYCCNT value --- lib/digital_signal/digital_signal.c | 21 +++++++++++++++++++-- lib/digital_signal/digital_signal.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index c7e8bbca5..727b64ca4 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -253,6 +253,7 @@ void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { sequence->sequence_used = 0; sequence->sequence_size = size; sequence->sequence = malloc(sequence->sequence_size); + sequence->send_time = 0; } DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { @@ -288,6 +289,10 @@ void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index digital_signal_prepare(signal); } +void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) { + sequence->send_time = send_time; +} + void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { furi_assert(sequence); furi_assert(signal_index < sequence->signals_size); @@ -352,7 +357,8 @@ void digital_signal_update_dma(DigitalSignal* signal) { LL_DMA_ClearFlag_TC2(DMA1); } -static bool digital_sequence_send_signal(DigitalSignal* signal) { +static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { + furi_assert(sequence); furi_assert(signal); /* the first iteration has to set up the whole machinery */ @@ -362,6 +368,17 @@ static bool digital_sequence_send_signal(DigitalSignal* signal) { return false; } digital_signal_setup_timer(); + + /* if the send time is specified, wait till the core timer passed beyond that time */ + if(sequence->send_time != 0) { + while(true) { + uint32_t delta = sequence->send_time - DWT->CYCCNT; + /* yeah, it's making use of underflows... */ + if(delta > 0x80000000) { + break; + } + } + } digital_signal_start_timer(); } else { /* configure next polarities and timings */ @@ -440,7 +457,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { sequence->signals_prolonged[signal_index] = needs_prolongation; } - bool success = digital_sequence_send_signal(sig); + bool success = digital_sequence_send_signal(sequence, sig); if(!success) { break; diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 8f6142258..94df13a60 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -42,6 +42,7 @@ typedef struct { bool* signals_prolonged; uint8_t* sequence; const GpioPin* gpio; + uint32_t send_time; } DigitalSequence; @@ -69,6 +70,7 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio); void digital_sequence_free(DigitalSequence* sequence); void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index, DigitalSignal* signal); +void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time); void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index); bool digital_sequence_send(DigitalSequence* sequence); void digital_sequence_clear(DigitalSequence* sequence); From 0a714fc1648cb70bfdc8985d33494650dbf7eb41 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Mon, 5 Dec 2022 09:36:45 +0100 Subject: [PATCH 013/216] fixed linter errors and undone function renaming --- lib/digital_signal/digital_signal.c | 104 ++++++++++++++-------------- lib/digital_signal/digital_signal.h | 18 +++-- lib/pulse_reader/pulse_reader.c | 68 +++++++++--------- lib/pulse_reader/pulse_reader.h | 16 +---- 4 files changed, 96 insertions(+), 110 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 727b64ca4..b78daab3d 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -6,11 +6,9 @@ #define TAG "DigitalSignal" - -#define F_TIM (64000000.0) -#define T_TIM 1562 /* 15.625 ns *100 */ -#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ - +#define F_TIM (64000000.0) +#define T_TIM 1562 /* 15.625 ns *100 */ +#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { DigitalSignal* signal = malloc(sizeof(DigitalSignal)); @@ -21,7 +19,7 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->reload_reg_entries = 0; signal->reload_reg_remainder = 0; - + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; @@ -32,7 +30,7 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; - signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->ARR); + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); signal->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; @@ -131,11 +129,11 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { return signal->edge_timings[edge_num]; } -void digital_signal_prepare(DigitalSignal* signal) { +void digital_signal_prepare_arr(DigitalSignal* signal) { furi_assert(signal); furi_assert(signal->gpio); furi_assert(signal->gpio->pin); - + /* set up signal polarities */ uint32_t bit_set = signal->gpio->pin; uint32_t bit_reset = signal->gpio->pin << 16; @@ -181,8 +179,8 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) { return false; } - signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff; - signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->BSRR); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buff; + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->BSRR); signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; signal->dma_config_timer.NbData = signal->reload_reg_entries; @@ -198,7 +196,6 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) { } static void digital_signal_setup_timer() { - digital_signal_stop_timer(); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); @@ -228,7 +225,7 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { /* single signal, add a temporary, terminating edge at the end */ signal->edge_timings[signal->edge_cnt++] = 10; - digital_signal_prepare(signal); + digital_signal_prepare_arr(signal); digital_signal_setup_dma(signal); digital_signal_setup_timer(); @@ -257,7 +254,6 @@ void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { } DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { - DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); sequence->gpio = gpio; @@ -277,7 +273,10 @@ void digital_sequence_free(DigitalSequence* sequence) { free(sequence); } -void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index, DigitalSignal* signal) { +void digital_sequence_set_signal( + DigitalSequence* sequence, + uint8_t signal_index, + DigitalSignal* signal) { furi_assert(sequence); furi_assert(signal); furi_assert(signal_index < sequence->signals_size); @@ -286,7 +285,7 @@ void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index signal->gpio = sequence->gpio; signal->reload_reg_remainder = 0; - digital_signal_prepare(signal); + digital_signal_prepare_arr(signal); } void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) { @@ -306,52 +305,48 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { } void digital_signal_update_dma(DigitalSignal* signal) { - volatile uint32_t dma1_data[] = { - /* R6 */ (uint32_t)&(DMA1_Channel1->CCR), + /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* R8 */ 2, - /* R9 */ (uint32_t)&(signal->gpio->port->BSRR), + /* R9 */ (uint32_t) & (signal->gpio->port->BSRR), /* R10 */ (uint32_t)signal->gpio_buff, - /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN }; + /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; volatile uint32_t dma2_data[] = { - /* R0 */ (uint32_t)&(DMA1_Channel2->CCR), + /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* R2 */ (uint32_t)signal->reload_reg_entries, - /* R3 */ (uint32_t)&(TIM2->ARR), + /* R3 */ (uint32_t) & (TIM2->ARR), /* R4 */ (uint32_t)signal->reload_reg_buff, - /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN }; + /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; - /* hurry when setting up next transfer */ asm volatile("\t" - "MOV r6, %[data1]\n\t" - "MOV r7, %[data2]\n\t" + "MOV r6, %[data1]\n\t" + "MOV r7, %[data2]\n\t" - "PUSH {r0-r12}\n\t" + "PUSH {r0-r12}\n\t" - "LDM r7, {r0-r5}\n\t" - "LDM r6, {r6-r11}\n\t" + "LDM r7, {r0-r5}\n\t" + "LDM r6, {r6-r11}\n\t" - "loop:\n\t" - "LDR r12, [r0, #4]\n\t" - "CMP r12, #0\n\t" - "BNE loop\n\t" + "loop:\n\t" + "LDR r12, [r0, #4]\n\t" + "CMP r12, #0\n\t" + "BNE loop\n\t" - "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ - "STR r11, [r6, #0]\n\t" /* enable channel again */ - "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ - "STR r5, [r0, #0]\n\t" /* enable channel again */ + "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ + "STR r11, [r6, #0]\n\t" /* enable channel again */ + "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ + "STR r5, [r0, #0]\n\t" /* enable channel again */ - "POP {r0-r12}\n\t" + "POP {r0-r12}\n\t" - : /* no outputs*/ - : /* inputs */ - [data1] "r" (dma1_data), - [data2] "r" (dma2_data) - : "r6", "r7" ); - + : /* no outputs*/ + : /* inputs */ + [data1] "r"(dma1_data), [data2] "r"(dma2_data) + : "r6", "r7"); LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC2(DMA1); @@ -360,7 +355,7 @@ void digital_signal_update_dma(DigitalSignal* signal) { static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { furi_assert(sequence); furi_assert(signal); - + /* the first iteration has to set up the whole machinery */ if(!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) { if(!digital_signal_setup_dma(signal)) { @@ -389,21 +384,20 @@ static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSigna } DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { - uint32_t edges = 0; for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { uint8_t signal_index = sequence->sequence[pos]; - DigitalSignal *sig = sequence->signals[signal_index]; + DigitalSignal* sig = sequence->signals[signal_index]; edges += sig->edge_cnt; } DigitalSignal* ret = digital_signal_alloc(edges); - + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { uint8_t signal_index = sequence->sequence[pos]; - DigitalSignal *sig = sequence->signals[signal_index]; + DigitalSignal* sig = sequence->signals[signal_index]; digital_signal_append(ret, sig); } @@ -429,10 +423,14 @@ bool digital_sequence_send(DigitalSequence* sequence) { for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { uint8_t signal_index = sequence->sequence[pos]; - DigitalSignal *sig = sequence->signals[signal_index]; + DigitalSignal* sig = sequence->signals[signal_index]; if(!sig) { - FURI_LOG_D(TAG, "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", signal_index, pos); + FURI_LOG_D( + TAG, + "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", + signal_index, + pos); break; } @@ -470,10 +468,10 @@ bool digital_sequence_send(DigitalSequence* sequence) { digital_signal_stop_timer(); digital_signal_stop_dma(); - + /* undo previously prolonged edges */ for(uint32_t pos = 0; pos < sequence->signals_size; pos++) { - DigitalSignal *sig = sequence->signals[pos]; + DigitalSignal* sig = sequence->signals[pos]; if(sig && sequence->signals_prolonged[pos]) { sig->edge_timings[0]--; diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 94df13a60..2e1a05522 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -13,11 +13,10 @@ extern "C" { #endif /* helper for easier signal generation */ -#define DIGITAL_SIGNAL_MS(x) (x*100000000UL) -#define DIGITAL_SIGNAL_US(x) (x*100000UL) -#define DIGITAL_SIGNAL_NS(x) (x*100UL) -#define DIGITAL_SIGNAL_PS(x) (x/10UL) - +#define DIGITAL_SIGNAL_MS(x) (x * 100000000UL) +#define DIGITAL_SIGNAL_US(x) (x * 100000UL) +#define DIGITAL_SIGNAL_NS(x) (x * 100UL) +#define DIGITAL_SIGNAL_PS(x) (x / 10UL) typedef struct { bool start_level; @@ -45,7 +44,6 @@ typedef struct { uint32_t send_time; } DigitalSequence; - DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); void digital_signal_free(DigitalSignal* signal); @@ -66,17 +64,17 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); - DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio); void digital_sequence_free(DigitalSequence* sequence); -void digital_sequence_set_signal(DigitalSequence* sequence, uint8_t signal_index, DigitalSignal* signal); +void digital_sequence_set_signal( + DigitalSequence* sequence, + uint8_t signal_index, + DigitalSignal* signal); void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time); void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index); bool digital_sequence_send(DigitalSequence* sequence); void digital_sequence_clear(DigitalSequence* sequence); - - #ifdef __cplusplus } #endif diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 18e7ee98d..20f993844 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -5,7 +5,6 @@ #include "pulse_reader.h" - #define GPIO_PIN_MAP(pin, prefix) \ (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ @@ -26,10 +25,7 @@ #define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE) - - PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { - PulseReader* signal = malloc(sizeof(PulseReader)); signal->timer_buffer = malloc(size * sizeof(uint32_t)); signal->gpio_buffer = malloc(size * sizeof(uint32_t)); @@ -43,14 +39,15 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { pulse_reader_set_bittime(signal, 1); signal->dma_config_timer.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; - signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT); + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->CNT); signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t) signal->timer_buffer; + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->timer_buffer; signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; signal->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; - signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_timer.PeriphRequest = + LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ signal->dma_config_timer.Priority = LL_DMA_PRIORITY_VERYHIGH; signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; @@ -59,7 +56,8 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; - signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_gpio.PeriphRequest = + LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; return signal; @@ -67,22 +65,22 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit) { switch(unit) { - case PulseReaderUnit64MHz: - signal->unit_multiplier = 1; - signal->unit_divider = 1; - break; - case PulseReaderUnitPicosecond: - signal->unit_multiplier = 15625; - signal->unit_divider = 1; - break; - case PulseReaderUnitNanosecond: - signal->unit_multiplier = 15625; - signal->unit_divider = 1000; - break; - case PulseReaderUnitMicrosecond: - signal->unit_multiplier = 15625; - signal->unit_divider = 1000000; - break; + case PulseReaderUnit64MHz: + signal->unit_multiplier = 1; + signal->unit_divider = 1; + break; + case PulseReaderUnitPicosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1; + break; + case PulseReaderUnitNanosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000; + break; + case PulseReaderUnitMicrosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000000; + break; } } @@ -104,7 +102,7 @@ uint32_t pulse_reader_samples(PulseReader* signal) { void pulse_reader_stop(PulseReader* signal) { LL_DMA_DisableChannel(DMA1, signal->dma_channel); - LL_DMA_DisableChannel(DMA1, signal->dma_channel+1); + LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); } @@ -113,8 +111,8 @@ void pulse_reader_start(PulseReader* signal) { /* configure DMA to read from a timer peripheral */ signal->dma_config_timer.NbData = signal->size; - signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->IDR); - signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buffer; + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->IDR); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer; signal->dma_config_gpio.NbData = signal->size; /* start counter */ @@ -126,14 +124,16 @@ void pulse_reader_start(PulseReader* signal) { LL_TIM_EnableCounter(TIM2); /* generator 0 gets fed by EXTI_LINEn */ - LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); + LL_DMAMUX_SetRequestSignalID( + NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); /* trigger on rising edge of the interrupt */ LL_DMAMUX_SetRequestGenPolarity(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING); /* now enable request generation again */ LL_DMAMUX_EnableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); /* we need the EXTI to be configured as interrupt generating line, but no ISR registered */ - furi_hal_gpio_init_ex(signal->gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + furi_hal_gpio_init_ex( + signal->gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); /* capture current timer */ signal->pos = 0; @@ -149,17 +149,16 @@ void pulse_reader_start(PulseReader* signal) { } uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { - uint32_t start_time = DWT->CYCCNT; - uint32_t timeout_ticks = timeout_us * (F_TIM2/1000000); + uint32_t timeout_ticks = timeout_us * (F_TIM2 / 1000000); do { /* get the DMA's next write position by reading "remaining length" register */ - uint32_t dma_pos = signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); + uint32_t dma_pos = + signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); /* the DMA has advanced in the ringbuffer */ if(dma_pos != signal->pos) { - uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value; uint32_t last_gpio_value = signal->gpio_value; @@ -179,7 +178,8 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { /* probably larger values, so choose a wider data type */ if(signal->unit_divider > 1) { - delta_unit = (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider); + delta_unit = + (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider); } else { delta_unit = delta * signal->unit_multiplier; } diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index f55a65931..564bf1063 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -14,9 +14,9 @@ extern "C" { #endif -#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL -#define PULSE_READER_LOST_EDGE 0xFFFFFFFEUL -#define F_TIM2 64000000UL +#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL +#define PULSE_READER_LOST_EDGE 0xFFFFFFFEUL +#define F_TIM2 64000000UL /** * unit of the edge durations to return @@ -28,7 +28,6 @@ typedef enum { PulseReaderUnitMicrosecond, } PulseReaderUnit; - typedef struct { bool start_level; uint32_t* timer_buffer; @@ -47,7 +46,6 @@ typedef struct { LL_DMA_InitTypeDef dma_config_gpio; } PulseReader; - /** Allocate a PulseReader object * * Allocates memory for a ringbuffer and initalizes the object @@ -57,7 +55,6 @@ typedef struct { */ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size); - /** Free a PulseReader object * * Frees all memory of the given object @@ -66,7 +63,6 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size); */ void pulse_reader_free(PulseReader* signal); - /** Start signal capturing * * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values @@ -75,7 +71,6 @@ void pulse_reader_free(PulseReader* signal); */ void pulse_reader_start(PulseReader* signal); - /** Stop signal capturing * * Frees DMA1, TIM2 and DMAMUX_REQ_GEN_0 @@ -84,7 +79,6 @@ void pulse_reader_start(PulseReader* signal); */ void pulse_reader_stop(PulseReader* signal); - /** Recevie a sample from ringbuffer * * Waits for the specified time until a new edge gets detected. @@ -99,7 +93,6 @@ void pulse_reader_stop(PulseReader* signal); */ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us); - /** Get available samples * * Get the number of available samples in the ringbuffer @@ -110,7 +103,6 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us); */ uint32_t pulse_reader_samples(PulseReader* signal); - /** Set timebase * * Set the timebase to be used when returning pulse duration. @@ -120,7 +112,6 @@ uint32_t pulse_reader_samples(PulseReader* signal); */ void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit); - /** Set bit time * * Set the number of timebase units per bit. @@ -134,7 +125,6 @@ void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit); */ void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time); - #ifdef __cplusplus } #endif From 9a6a796804ac07999216fcb02b182147ebf7439a Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Mon, 5 Dec 2022 10:32:44 +0100 Subject: [PATCH 014/216] fixed renaming --- lib/digital_signal/digital_signal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 2e1a05522..9a91c8b45 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -54,7 +54,7 @@ void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level) bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b); -void digital_signal_prepare(DigitalSignal* signal); +void digital_signal_prepare_arr(DigitalSignal* signal); bool digital_signal_get_start_level(DigitalSignal* signal); From b24c0cd97fbaa1c41758e5a4e9af6185c33472df Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Mon, 5 Dec 2022 10:36:15 +0100 Subject: [PATCH 015/216] flagged functions in api_symbols.csv --- firmware/targets/f7/api_symbols.csv | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d0c6b36ad..63fb64a00 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -736,6 +736,15 @@ Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, u Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" Function,-,difftime,double,"time_t, time_t" +Function,-,digital_sequence_add,void,"DigitalSequence*, uint8_t" +Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" +Function,-,digital_sequence_clear,void,DigitalSequence* +Function,-,digital_sequence_free,void,DigitalSequence* +Function,-,digital_sequence_send,_Bool,DigitalSequence* +Function,-,digital_sequence_set_sendtime,void,"DigitalSequence*, uint32_t" +Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*" +Function,-,digital_signal_add,void,"DigitalSignal*, uint32_t" +Function,-,digital_signal_add_pulse,void,"DigitalSignal*, uint32_t, _Bool" Function,-,digital_signal_alloc,DigitalSignal*,uint32_t Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*" Function,-,digital_signal_free,void,DigitalSignal* From 302739d543ebb95f17056b3cfaed6ac92d5beea3 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Mon, 5 Dec 2022 12:19:05 +0100 Subject: [PATCH 016/216] allow gpio field to stay uninitialized in digital_signal_prepare_arr() --- lib/digital_signal/digital_signal.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index b78daab3d..9ba5cc901 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -131,19 +131,19 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { void digital_signal_prepare_arr(DigitalSignal* signal) { furi_assert(signal); - furi_assert(signal->gpio); - furi_assert(signal->gpio->pin); /* set up signal polarities */ - uint32_t bit_set = signal->gpio->pin; - uint32_t bit_reset = signal->gpio->pin << 16; + if(signal->gpio) { + uint32_t bit_set = signal->gpio->pin; + uint32_t bit_reset = signal->gpio->pin << 16; - if(signal->start_level) { - signal->gpio_buff[0] = bit_set; - signal->gpio_buff[1] = bit_reset; - } else { - signal->gpio_buff[0] = bit_reset; - signal->gpio_buff[1] = bit_set; + if(signal->start_level) { + signal->gpio_buff[0] = bit_set; + signal->gpio_buff[1] = bit_reset; + } else { + signal->gpio_buff[0] = bit_reset; + signal->gpio_buff[1] = bit_set; + } } /* set up edge timings */ From 035d630ff90f9bf29f29336fc78465b3517fa106 Mon Sep 17 00:00:00 2001 From: g3gg0 Date: Thu, 15 Dec 2022 15:29:16 +0100 Subject: [PATCH 017/216] fix test cases to match (expected) implementation --- assets/unit_tests/nfc/nfc_nfca_signal_long.nfc | 2 +- assets/unit_tests/nfc/nfc_nfca_signal_short.nfc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc b/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc index fae69cb5c..dd6a2ff8e 100644 --- a/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc +++ b/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc @@ -3,4 +3,4 @@ Version: 1 Data length: 18 Plain data: f1 99 41 43 a1 2f 23 01 de f3 c5 8d 91 4b 1e 50 4a c9 Timings length: 1304 -Timings: 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 640 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 0 +Timings: 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 640 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc b/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc index 3b7e2d9e9..f447fca26 100644 --- a/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc +++ b/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc @@ -3,4 +3,4 @@ Version: 1 Data length: 4 Plain data: 14 d8 a0 c9 Timings length: 296 -Timings: 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 36 37 37 37 37 36 37 0 +Timings: 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 36 37 37 37 37 36 37 37 From b5b5abac273d50d2b886c5e119ec16e3f55609ca Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 20 Dec 2022 18:49:29 +0400 Subject: [PATCH 018/216] pulse_reader: build as static library Signed-off-by: g3gg0.de --- firmware/targets/f7/api_symbols.csv | 9 +++++++++ firmware/targets/f7/target.json | 1 + lib/SConscript | 2 ++ lib/pulse_reader/SConscript | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 lib/pulse_reader/SConscript diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 63fb64a00..7b80eb8aa 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -173,6 +173,7 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/subghz/blocks/const.h,, Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, @@ -2166,6 +2167,14 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t" Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" +Function,+,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t" +Function,+,pulse_reader_free,void,PulseReader* +Function,+,pulse_reader_receive,uint32_t,"PulseReader*, int" +Function,+,pulse_reader_samples,uint32_t,PulseReader* +Function,+,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" +Function,+,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" +Function,+,pulse_reader_start,void,PulseReader* +Function,+,pulse_reader_stop,void,PulseReader* Function,-,putc,int,"int, FILE*" Function,-,putc_unlocked,int,"int, FILE*" Function,-,putchar,int,int diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 14bb1cd0c..0d2367b3a 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -28,6 +28,7 @@ "flipperformat", "toolbox", "nfc", + "pulse_reader", "microtar", "usb_stm32", "st25rfal002", diff --git a/lib/SConscript b/lib/SConscript index 51f6f7544..23c74b334 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -15,6 +15,7 @@ env.Append( Dir("u8g2"), Dir("update_util"), Dir("print"), + Dir("pulse_reader"), ], ) @@ -94,6 +95,7 @@ libs = env.BuildModules( "mbedtls", "subghz", "nfc", + "pulse_reader", "appframe", "misc", "lfrfid", diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript new file mode 100644 index 000000000..416ad4a27 --- /dev/null +++ b/lib/pulse_reader/SConscript @@ -0,0 +1,19 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/pulse_reader", + ], + SDK_HEADERS=[ + File("pulse_reader.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="pulse_reader") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") \ No newline at end of file From 396ebe1ad80c8bbb7728b14fa6d95b43b6103f06 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 01:01:16 +0100 Subject: [PATCH 019/216] fix starting level detection in pulse_reader --- lib/pulse_reader/pulse_reader.c | 2 +- lib/pulse_reader/pulse_reader.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 20f993844..64fde7fc9 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -137,9 +137,9 @@ void pulse_reader_start(PulseReader* signal) { /* capture current timer */ signal->pos = 0; - signal->start_level = furi_hal_gpio_read(signal->gpio); signal->timer_value = TIM2->CNT; signal->gpio_mask = signal->gpio->pin; + signal->gpio_value = signal->gpio->port->IDR & signal->gpio_mask; /* now set up DMA with these settings */ LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer); diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index 564bf1063..b4e6bca57 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -29,7 +29,6 @@ typedef enum { } PulseReaderUnit; typedef struct { - bool start_level; uint32_t* timer_buffer; uint32_t* gpio_buffer; uint32_t size; @@ -65,7 +64,8 @@ void pulse_reader_free(PulseReader* signal); /** Start signal capturing * - * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values + * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values. + * Ensure that interrupts are always enabled, as the used EXTI line is handled as one. * * @param[in] signal previously allocated PulseReader object. */ From e56cd5165afb38ee36373d0d205bf954ad4605b0 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 01:06:22 +0100 Subject: [PATCH 020/216] added unit test for pulse_reader --- applications/debug/unit_tests/nfc/nfc_test.c | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 54bdd5909..3b3a44431 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -1,10 +1,12 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -179,6 +181,153 @@ MU_TEST(nfc_digital_signal_test) { "NFC long digital signal test failed\r\n"); } +static bool nfc_test_pulse_reader_toggle( + uint32_t usec_low, + uint32_t usec_high, + uint32_t period_count, + uint32_t tolerance) { + furi_assert(nfc_test); + + bool success = false; + uint32_t pulses = 0; + const GpioPin* gpio_in = &gpio_ext_pa6; + const GpioPin* gpio_out = &gpio_ext_pa7; + PulseReader* reader = NULL; + + do { + reader = pulse_reader_alloc(gpio_in, 512); + + if(!reader) { + FURI_LOG_E(TAG, "failed to allocate pulse reader"); + break; + } + + /* use TIM1 to create a specific number of pulses with defined duty cycle + but first set the IO to high, so the low/high pulse can get detected */ + furi_hal_gpio_init(gpio_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(gpio_out, true); + + LL_TIM_DeInit(TIM1); + + LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetRepetitionCounter(TIM1, 0); + LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM1); + + LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH1); + LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM2); + 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_EnableAllOutputs(TIM1); + + /* now calculate the TIM1 period and compare values */ + uint32_t freq_div = 64 * (usec_low + usec_high); + uint32_t prescaler = freq_div / 0x10000LU; + uint32_t period = freq_div / (prescaler + 1); + uint32_t compare = 64 * usec_low / (prescaler + 1); + + LL_TIM_SetPrescaler(TIM1, prescaler); + LL_TIM_SetAutoReload(TIM1, period - 1); + LL_TIM_SetCounter(TIM1, period - 1); + LL_TIM_OC_SetCompareCH1(TIM1, compare); + + /* timer is ready to launch, now start the pulse reader */ + pulse_reader_set_timebase(reader, PulseReaderUnitMicrosecond); + pulse_reader_start(reader); + + /* and quickly enable and switch over the GPIO to the generated signal */ + LL_TIM_EnableCounter(TIM1); + furi_hal_gpio_init_ex( + gpio_out, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn1TIM1); + + /* now it's time to parse the pulses received by the reader */ + uint32_t timer_pulses = period_count; + uint32_t prev_cnt = 0; + + while(timer_pulses > 0) { + /* whenever the counter gets reset, we went through a full period */ + uint32_t cur_cnt = LL_TIM_GetCounter(TIM1); + if(cur_cnt < prev_cnt) { + timer_pulses--; + } + prev_cnt = cur_cnt; + } + /* quickly halt the counter to keep a static signal */ + LL_TIM_DisableCounter(TIM1); + + do { + /* as all edges were sampled asynchronously, the timeout can be zero */ + uint32_t length = pulse_reader_receive(reader, 0); + + /* in the last pulse, we expect a "no edge" return value. if seen that, test succeeded. */ + if(pulses > period_count * 2) { + if(length != PULSE_READER_NO_EDGE) { + FURI_LOG_E( + TAG, + "last pulse expected to be PULSE_READER_NO_EDGE, but was %lu.", + length); + break; + } + success = true; + break; + } + + /* else we shall never see "no edge" or "lost edge" */ + if(length == PULSE_READER_NO_EDGE) { + FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_NO_EDGE", pulses); + break; + } + if(length == PULSE_READER_LOST_EDGE) { + FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_LOST_EDGE", pulses); + break; + } + + if(pulses > 0) { + /* throw away the first pulse, which is the 1->0 from the first start and will be irrelevant for our test */ + bool phase = ((pulses - 1) % 2) == 1; + uint32_t expected = phase ? usec_high : usec_low; + uint32_t deviation = abs((int32_t)length - (int32_t)expected); + + if(deviation > tolerance) { + FURI_LOG_E( + TAG, + "%lu. pulse expected %lu, but pulse was %lu.", + pulses, + expected, + length); + break; + } + } + pulses++; + } while(true); + } while(false); + + if(reader != NULL) { + pulse_reader_stop(reader); + pulse_reader_free(reader); + } + + LL_TIM_DeInit(TIM1); + furi_hal_gpio_init_simple(gpio_in, GpioModeAnalog); + furi_hal_gpio_init_simple(gpio_out, GpioModeAnalog); + + return success; +} + +MU_TEST(nfc_pulse_reader_test) { + mu_assert(nfc_test_pulse_reader_toggle(1500, 2500, 50, 10), "1 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(10000, 10000, 10, 10), "10 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(100000, 100000, 5, 50), "100 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(100, 900, 50, 10), "1 ms asymmetric signal failed\r\n"); + mu_assert( + nfc_test_pulse_reader_toggle(3333, 6666, 10, 10), "10 ms asymmetric signal failed\r\n"); + mu_assert( + nfc_test_pulse_reader_toggle(25000, 75000, 5, 10), "100 ms asymmetric signal failed\r\n"); +} + MU_TEST(mf_classic_dict_test) { MfClassicDict* instance = NULL; uint64_t key = 0; @@ -513,6 +662,7 @@ MU_TEST(mf_classic_4k_7b_file_test) { MU_TEST_SUITE(nfc) { nfc_test_alloc(); + MU_RUN_TEST(nfc_pulse_reader_test); MU_RUN_TEST(nfca_file_test); MU_RUN_TEST(mf_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); From 9cf16bdfe4a9ccf81b6fa6ca282bbf81443853ba Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 01:15:22 +0100 Subject: [PATCH 021/216] change pulse reader test timings to 1, 10 and 100 ms --- applications/debug/unit_tests/nfc/nfc_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 3b3a44431..98b996212 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -318,9 +318,9 @@ static bool nfc_test_pulse_reader_toggle( } MU_TEST(nfc_pulse_reader_test) { - mu_assert(nfc_test_pulse_reader_toggle(1500, 2500, 50, 10), "1 ms signal failed\r\n"); - mu_assert(nfc_test_pulse_reader_toggle(10000, 10000, 10, 10), "10 ms signal failed\r\n"); - mu_assert(nfc_test_pulse_reader_toggle(100000, 100000, 5, 50), "100 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(500, 500, 50, 10), "1 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(5000, 5000, 10, 10), "10 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(50000, 50000, 5, 50), "100 ms signal failed\r\n"); mu_assert(nfc_test_pulse_reader_toggle(100, 900, 50, 10), "1 ms asymmetric signal failed\r\n"); mu_assert( nfc_test_pulse_reader_toggle(3333, 6666, 10, 10), "10 ms asymmetric signal failed\r\n"); From 146061e631fa6d446db1a76c9f8141b5d96ffca6 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 01:26:16 +0100 Subject: [PATCH 022/216] fine tuned timings for pulse_reader test --- applications/debug/unit_tests/nfc/nfc_test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 98b996212..87622f3d3 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -255,7 +255,9 @@ static bool nfc_test_pulse_reader_toggle( } prev_cnt = cur_cnt; } - /* quickly halt the counter to keep a static signal */ + /* quickly halt the counter to keep a static signal. we might get some delay here due to scheduling, + causing the timer to continue racing. there is currently no workaround, as disabling interrupts will + defunct the pulse_reader */ LL_TIM_DisableCounter(TIM1); do { @@ -318,12 +320,10 @@ static bool nfc_test_pulse_reader_toggle( } MU_TEST(nfc_pulse_reader_test) { - mu_assert(nfc_test_pulse_reader_toggle(500, 500, 50, 10), "1 ms signal failed\r\n"); mu_assert(nfc_test_pulse_reader_toggle(5000, 5000, 10, 10), "10 ms signal failed\r\n"); mu_assert(nfc_test_pulse_reader_toggle(50000, 50000, 5, 50), "100 ms signal failed\r\n"); - mu_assert(nfc_test_pulse_reader_toggle(100, 900, 50, 10), "1 ms asymmetric signal failed\r\n"); mu_assert( - nfc_test_pulse_reader_toggle(3333, 6666, 10, 10), "10 ms asymmetric signal failed\r\n"); + nfc_test_pulse_reader_toggle(3333, 6667, 10, 10), "10 ms asymmetric signal failed\r\n"); mu_assert( nfc_test_pulse_reader_toggle(25000, 75000, 5, 10), "100 ms asymmetric signal failed\r\n"); } From a34f2d290382bc6dac61859a2eb92efa1fb160c5 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 15:38:03 +0100 Subject: [PATCH 023/216] pulse_reader_stop now deinits GPIO as recommended by @gornekich --- lib/pulse_reader/pulse_reader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 64fde7fc9..8b35f6d18 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -105,6 +105,7 @@ void pulse_reader_stop(PulseReader* signal) { LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); + furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog); } void pulse_reader_start(PulseReader* signal) { From f56835cb655fa15e7895fb84f65f4f45f20d9d03 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 17:36:51 +0100 Subject: [PATCH 024/216] ran format_py --- lib/pulse_reader/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript index 416ad4a27..5a72b953f 100644 --- a/lib/pulse_reader/SConscript +++ b/lib/pulse_reader/SConscript @@ -16,4 +16,4 @@ sources = libenv.GlobRecursive("*.c*") lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") \ No newline at end of file +Return("lib") From 4d09a50fbb4d444b1327cc35a12196cd1fe0644e Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 21 Dec 2022 23:17:06 +0400 Subject: [PATCH 025/216] pulse_reader: remove from API, allow to link with faps Signed-off-by: g3gg0.de --- firmware/targets/f7/api_symbols.csv | 16 ++++++++-------- lib/pulse_reader/SConscript | 8 ++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7b80eb8aa..bfd87214c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2167,14 +2167,14 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t" Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" -Function,+,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t" -Function,+,pulse_reader_free,void,PulseReader* -Function,+,pulse_reader_receive,uint32_t,"PulseReader*, int" -Function,+,pulse_reader_samples,uint32_t,PulseReader* -Function,+,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" -Function,+,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" -Function,+,pulse_reader_start,void,PulseReader* -Function,+,pulse_reader_stop,void,PulseReader* +Function,-,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t" +Function,-,pulse_reader_free,void,PulseReader* +Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int" +Function,-,pulse_reader_samples,uint32_t,PulseReader* +Function,-,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" +Function,-,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" +Function,-,pulse_reader_start,void,PulseReader* +Function,-,pulse_reader_stop,void,PulseReader* Function,-,putc,int,"int, FILE*" Function,-,putc_unlocked,int,"int, FILE*" Function,-,putchar,int,int diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript index 5a72b953f..f00851a20 100644 --- a/lib/pulse_reader/SConscript +++ b/lib/pulse_reader/SConscript @@ -12,6 +12,14 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="pulse_reader") libenv.ApplyLibFlags() +libenv.AppendUnique( + CCFLAGS=[ + # Required for lib to be linkable with .faps + "-mword-relocations", + "-mlong-calls", + ], +) + sources = libenv.GlobRecursive("*.c*") lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) From 67b02b7785cebc7f39ceac4705d21088b854cd49 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 21:54:33 +0100 Subject: [PATCH 026/216] remove unit test for pulse_reader again --- applications/debug/unit_tests/nfc/nfc_test.c | 150 ------------------- 1 file changed, 150 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 87622f3d3..54bdd5909 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -1,12 +1,10 @@ #include #include -#include #include #include #include #include #include -#include #include #include @@ -181,153 +179,6 @@ MU_TEST(nfc_digital_signal_test) { "NFC long digital signal test failed\r\n"); } -static bool nfc_test_pulse_reader_toggle( - uint32_t usec_low, - uint32_t usec_high, - uint32_t period_count, - uint32_t tolerance) { - furi_assert(nfc_test); - - bool success = false; - uint32_t pulses = 0; - const GpioPin* gpio_in = &gpio_ext_pa6; - const GpioPin* gpio_out = &gpio_ext_pa7; - PulseReader* reader = NULL; - - do { - reader = pulse_reader_alloc(gpio_in, 512); - - if(!reader) { - FURI_LOG_E(TAG, "failed to allocate pulse reader"); - break; - } - - /* use TIM1 to create a specific number of pulses with defined duty cycle - but first set the IO to high, so the low/high pulse can get detected */ - furi_hal_gpio_init(gpio_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - furi_hal_gpio_write(gpio_out, true); - - LL_TIM_DeInit(TIM1); - - LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); - LL_TIM_SetRepetitionCounter(TIM1, 0); - LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1); - LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM1); - - LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH1); - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM2); - 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_EnableAllOutputs(TIM1); - - /* now calculate the TIM1 period and compare values */ - uint32_t freq_div = 64 * (usec_low + usec_high); - uint32_t prescaler = freq_div / 0x10000LU; - uint32_t period = freq_div / (prescaler + 1); - uint32_t compare = 64 * usec_low / (prescaler + 1); - - LL_TIM_SetPrescaler(TIM1, prescaler); - LL_TIM_SetAutoReload(TIM1, period - 1); - LL_TIM_SetCounter(TIM1, period - 1); - LL_TIM_OC_SetCompareCH1(TIM1, compare); - - /* timer is ready to launch, now start the pulse reader */ - pulse_reader_set_timebase(reader, PulseReaderUnitMicrosecond); - pulse_reader_start(reader); - - /* and quickly enable and switch over the GPIO to the generated signal */ - LL_TIM_EnableCounter(TIM1); - furi_hal_gpio_init_ex( - gpio_out, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn1TIM1); - - /* now it's time to parse the pulses received by the reader */ - uint32_t timer_pulses = period_count; - uint32_t prev_cnt = 0; - - while(timer_pulses > 0) { - /* whenever the counter gets reset, we went through a full period */ - uint32_t cur_cnt = LL_TIM_GetCounter(TIM1); - if(cur_cnt < prev_cnt) { - timer_pulses--; - } - prev_cnt = cur_cnt; - } - /* quickly halt the counter to keep a static signal. we might get some delay here due to scheduling, - causing the timer to continue racing. there is currently no workaround, as disabling interrupts will - defunct the pulse_reader */ - LL_TIM_DisableCounter(TIM1); - - do { - /* as all edges were sampled asynchronously, the timeout can be zero */ - uint32_t length = pulse_reader_receive(reader, 0); - - /* in the last pulse, we expect a "no edge" return value. if seen that, test succeeded. */ - if(pulses > period_count * 2) { - if(length != PULSE_READER_NO_EDGE) { - FURI_LOG_E( - TAG, - "last pulse expected to be PULSE_READER_NO_EDGE, but was %lu.", - length); - break; - } - success = true; - break; - } - - /* else we shall never see "no edge" or "lost edge" */ - if(length == PULSE_READER_NO_EDGE) { - FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_NO_EDGE", pulses); - break; - } - if(length == PULSE_READER_LOST_EDGE) { - FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_LOST_EDGE", pulses); - break; - } - - if(pulses > 0) { - /* throw away the first pulse, which is the 1->0 from the first start and will be irrelevant for our test */ - bool phase = ((pulses - 1) % 2) == 1; - uint32_t expected = phase ? usec_high : usec_low; - uint32_t deviation = abs((int32_t)length - (int32_t)expected); - - if(deviation > tolerance) { - FURI_LOG_E( - TAG, - "%lu. pulse expected %lu, but pulse was %lu.", - pulses, - expected, - length); - break; - } - } - pulses++; - } while(true); - } while(false); - - if(reader != NULL) { - pulse_reader_stop(reader); - pulse_reader_free(reader); - } - - LL_TIM_DeInit(TIM1); - furi_hal_gpio_init_simple(gpio_in, GpioModeAnalog); - furi_hal_gpio_init_simple(gpio_out, GpioModeAnalog); - - return success; -} - -MU_TEST(nfc_pulse_reader_test) { - mu_assert(nfc_test_pulse_reader_toggle(5000, 5000, 10, 10), "10 ms signal failed\r\n"); - mu_assert(nfc_test_pulse_reader_toggle(50000, 50000, 5, 50), "100 ms signal failed\r\n"); - mu_assert( - nfc_test_pulse_reader_toggle(3333, 6667, 10, 10), "10 ms asymmetric signal failed\r\n"); - mu_assert( - nfc_test_pulse_reader_toggle(25000, 75000, 5, 10), "100 ms asymmetric signal failed\r\n"); -} - MU_TEST(mf_classic_dict_test) { MfClassicDict* instance = NULL; uint64_t key = 0; @@ -662,7 +513,6 @@ MU_TEST(mf_classic_4k_7b_file_test) { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfc_pulse_reader_test); MU_RUN_TEST(nfca_file_test); MU_RUN_TEST(mf_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); From f08c8d6a1dee43199f6a78047d323258f1561696 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 28 Dec 2022 14:40:29 +0100 Subject: [PATCH 027/216] pulse_reader: add call to set GPIO pull direction --- firmware/targets/f7/api_symbols.csv | 1 + lib/pulse_reader/pulse_reader.c | 7 ++++++- lib/pulse_reader/pulse_reader.h | 11 +++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index bfd87214c..2edbdb16d 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2172,6 +2172,7 @@ Function,-,pulse_reader_free,void,PulseReader* Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int" Function,-,pulse_reader_samples,uint32_t,PulseReader* Function,-,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" +Function,-,pulse_reader_set_pull,void,"PulseReader*, GpioPull" Function,-,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" Function,-,pulse_reader_start,void,PulseReader* Function,-,pulse_reader_stop,void,PulseReader* diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 8b35f6d18..3d9508f9a 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -31,6 +31,7 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { signal->gpio_buffer = malloc(size * sizeof(uint32_t)); signal->dma_channel = LL_DMA_CHANNEL_4; signal->gpio = gpio; + signal->pull = GpioPullNo; signal->size = size; signal->timer_value = 0; signal->pos = 0; @@ -88,6 +89,10 @@ void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) { signal->bit_time = bit_time; } +void pulse_reader_set_pull(PulseReader* signal, GpioPull pull) { + signal->pull = pull; +} + void pulse_reader_free(PulseReader* signal) { free(signal->timer_buffer); free(signal->gpio_buffer); @@ -134,7 +139,7 @@ void pulse_reader_start(PulseReader* signal) { /* we need the EXTI to be configured as interrupt generating line, but no ISR registered */ furi_hal_gpio_init_ex( - signal->gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + signal->gpio, GpioModeInterruptRiseFall, signal->pull, GpioSpeedVeryHigh, GpioAltFnUnused); /* capture current timer */ signal->pos = 0; diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index b4e6bca57..be0ad7012 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -41,6 +41,7 @@ typedef struct { uint32_t bit_time; uint32_t dma_channel; const GpioPin* gpio; + GpioPull pull; LL_DMA_InitTypeDef dma_config_timer; LL_DMA_InitTypeDef dma_config_gpio; } PulseReader; @@ -125,6 +126,16 @@ void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit); */ void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time); +/** Set GPIO pull direction + * + * Some GPIOs need pulldown, others don't. By default the + * pull direction is GpioPullNo. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] pull GPIO pull direction + */ +void pulse_reader_set_pull(PulseReader* signal, GpioPull pull); + #ifdef __cplusplus } #endif From c18cf71646ed1fa3e167efc470dae568dc96c2f9 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 28 Dec 2022 22:43:39 +0100 Subject: [PATCH 028/216] make structures private, add C implementation of digital_signal_update_dma() --- lib/digital_signal/digital_signal.c | 179 ++++++++++++++++++---------- lib/digital_signal/digital_signal.h | 29 ++--- lib/pulse_reader/pulse_reader.c | 25 +++- lib/pulse_reader/pulse_reader.h | 23 +--- 4 files changed, 147 insertions(+), 109 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 9ba5cc901..12b543273 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -4,6 +4,30 @@ #include #include +#include +#include + +struct DigitalSequence { + uint8_t signals_size; + bool bake; + uint32_t sequence_used; + uint32_t sequence_size; + DigitalSignal** signals; + bool* signals_prolonged; + uint8_t* sequence; + const GpioPin* gpio; + uint32_t send_time; +}; + +struct DigitalSignalInternals { + uint32_t reload_reg_entries; + uint32_t reload_reg_remainder; + uint32_t gpio_buff[2]; + const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; +}; + #define TAG "DigitalSignal" #define F_TIM (64000000.0) @@ -17,28 +41,29 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->edge_cnt = 0; signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); - signal->reload_reg_entries = 0; - signal->reload_reg_remainder = 0; - signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; - signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->dma_config_gpio.NbData = 2; - signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + signal->internals = malloc(sizeof(DigitalSignalInternals)); + signal->internals->reload_reg_entries = 0; + signal->internals->reload_reg_remainder = 0; + signal->internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->internals->dma_config_gpio.NbData = 2; + signal->internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; - signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - signal->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; - signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; + signal->internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + signal->internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + signal->internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -48,6 +73,7 @@ void digital_signal_free(DigitalSignal* signal) { free(signal->edge_timings); free(signal->reload_reg_buff); + free(signal->internals); free(signal); } @@ -133,29 +159,30 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { furi_assert(signal); /* set up signal polarities */ - if(signal->gpio) { - uint32_t bit_set = signal->gpio->pin; - uint32_t bit_reset = signal->gpio->pin << 16; + if(signal->internals->gpio) { + uint32_t bit_set = signal->internals->gpio->pin; + uint32_t bit_reset = signal->internals->gpio->pin << 16; if(signal->start_level) { - signal->gpio_buff[0] = bit_set; - signal->gpio_buff[1] = bit_reset; + signal->internals->gpio_buff[0] = bit_set; + signal->internals->gpio_buff[1] = bit_reset; } else { - signal->gpio_buff[0] = bit_reset; - signal->gpio_buff[1] = bit_set; + signal->internals->gpio_buff[0] = bit_reset; + signal->internals->gpio_buff[1] = bit_set; } } /* set up edge timings */ - signal->reload_reg_entries = 0; + signal->internals->reload_reg_entries = 0; for(size_t pos = 0; pos < signal->edge_cnt; pos++) { - uint32_t pulse_duration = signal->edge_timings[pos] + signal->reload_reg_remainder; + uint32_t pulse_duration = + signal->edge_timings[pos] + signal->internals->reload_reg_remainder; uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; - signal->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); + signal->internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); if(pulse_ticks > 1) { - signal->reload_reg_buff[signal->reload_reg_entries++] = pulse_ticks - 1; + signal->reload_reg_buff[signal->internals->reload_reg_entries++] = pulse_ticks - 1; } } } @@ -175,18 +202,20 @@ static void digital_signal_stop_timer() { static bool digital_signal_setup_dma(DigitalSignal* signal) { furi_assert(signal); - if(!signal->reload_reg_entries) { + if(!signal->internals->reload_reg_entries) { return false; } - signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buff; - signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->BSRR); - signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - signal->dma_config_timer.NbData = signal->reload_reg_entries; + signal->internals->dma_config_gpio.MemoryOrM2MDstAddress = + (uint32_t)signal->internals->gpio_buff; + signal->internals->dma_config_gpio.PeriphOrM2MSrcAddress = + (uint32_t) & (signal->internals->gpio->port->BSRR); + signal->internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; + signal->internals->dma_config_timer.NbData = signal->internals->reload_reg_entries; /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->dma_config_gpio); - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->internals->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->internals->dma_config_timer); /* enable both DMA channels */ LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); @@ -220,8 +249,9 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { } /* Configure gpio as output */ - signal->gpio = gpio; - furi_hal_gpio_init(signal->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + signal->internals->gpio = gpio; + furi_hal_gpio_init( + signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); /* single signal, add a temporary, terminating edge at the end */ signal->edge_timings[signal->edge_cnt++] = 10; @@ -282,8 +312,8 @@ void digital_sequence_set_signal( furi_assert(signal_index < sequence->signals_size); sequence->signals[signal_index] = signal; - signal->gpio = sequence->gpio; - signal->reload_reg_remainder = 0; + signal->internals->gpio = sequence->gpio; + signal->internals->reload_reg_remainder = 0; digital_signal_prepare_arr(signal); } @@ -304,54 +334,71 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { sequence->sequence[sequence->sequence_used++] = signal_index; } -void digital_signal_update_dma(DigitalSignal* signal) { +#if defined(DIGITAL_SIGNAL_PORTABLE_CODE) + +static void digital_signal_update_dma(DigitalSignal* signal) { + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->internals->gpio_buff); + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->internals->reload_reg_entries); + + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); +} + +#else + +static void digital_signal_update_dma(DigitalSignal* signal) { volatile uint32_t dma1_data[] = { /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* R8 */ 2, - /* R9 */ (uint32_t) & (signal->gpio->port->BSRR), - /* R10 */ (uint32_t)signal->gpio_buff, + /* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR), + /* R10 */ (uint32_t)signal->internals->gpio_buff, /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; volatile uint32_t dma2_data[] = { /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, - /* R2 */ (uint32_t)signal->reload_reg_entries, + /* R2 */ (uint32_t)signal->internals->reload_reg_entries, /* R3 */ (uint32_t) & (TIM2->ARR), /* R4 */ (uint32_t)signal->reload_reg_buff, /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; /* hurry when setting up next transfer */ - asm volatile("\t" - "MOV r6, %[data1]\n\t" - "MOV r7, %[data2]\n\t" + asm volatile( + "\t" + "MOV r6, %[data1]\n\t" + "MOV r7, %[data2]\n\t" - "PUSH {r0-r12}\n\t" + "PUSH {r0-r12}\n\t" - "LDM r7, {r0-r5}\n\t" - "LDM r6, {r6-r11}\n\t" + "LDM r7, {r0-r5}\n\t" /* prepare registers with values to write into DMA config */ + "LDM r6, {r6-r11}\n\t" - "loop:\n\t" - "LDR r12, [r0, #4]\n\t" - "CMP r12, #0\n\t" - "BNE loop\n\t" + "loop:\n\t" + "LDR r12, [r0, #4]\n\t" /* read DMA_CNDTRx to get remaining transfers */ + "CMP r12, #0\n\t" + "BNE loop\n\t" - "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ - "STR r11, [r6, #0]\n\t" /* enable channel again */ - "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ - "STR r5, [r0, #0]\n\t" /* enable channel again */ + "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ + "STR r11, [r6, #0]\n\t" /* enable channel again */ + "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ + "STR r5, [r0, #0]\n\t" /* enable channel again */ - "POP {r0-r12}\n\t" + "POP {r0-r12}\n\t" - : /* no outputs*/ - : /* inputs */ - [data1] "r"(dma1_data), [data2] "r"(dma2_data) - : "r6", "r7"); + : /* no outputs*/ + : /* inputs */ + [data1] "r"(dma1_data), [data2] "r"(dma2_data) + : "r6", "r7"); LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC2(DMA1); } +#endif + static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { furi_assert(sequence); furi_assert(signal); @@ -443,7 +490,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { } /* update the total remainder */ - remainder += sig->reload_reg_remainder; + remainder += sig->internals->reload_reg_remainder; /* do we need to update the prolongation? */ if(needs_prolongation != sequence->signals_prolonged[signal_index]) { diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 9a91c8b45..2cb107486 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -5,8 +5,6 @@ #include #include -#include -#include #ifdef __cplusplus extern "C" { @@ -18,31 +16,20 @@ extern "C" { #define DIGITAL_SIGNAL_NS(x) (x * 100UL) #define DIGITAL_SIGNAL_PS(x) (x / 10UL) -typedef struct { +/* using an anonymous type for the internals */ +typedef struct DigitalSignalInternals DigitalSignalInternals; + +/* and a public one for accessing user-side fields */ +typedef struct DigitalSignal { bool start_level; uint32_t edge_cnt; uint32_t edges_max_cnt; uint32_t* edge_timings; - uint32_t* reload_reg_buff; - uint32_t reload_reg_entries; - uint32_t reload_reg_remainder; - uint32_t gpio_buff[2]; - const GpioPin* gpio; - LL_DMA_InitTypeDef dma_config_gpio; - LL_DMA_InitTypeDef dma_config_timer; + uint32_t* reload_reg_buff; /* internal, but used by unit tests */ + DigitalSignalInternals* internals; } DigitalSignal; -typedef struct { - uint8_t signals_size; - bool bake; - uint32_t sequence_used; - uint32_t sequence_size; - DigitalSignal** signals; - bool* signals_prolonged; - uint8_t* sequence; - const GpioPin* gpio; - uint32_t send_time; -} DigitalSequence; +typedef struct DigitalSequence DigitalSequence; DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 3d9508f9a..84ce2ff23 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -1,9 +1,32 @@ +#include "pulse_reader.h" + #include #include #include #include -#include "pulse_reader.h" +#include +#include +#include +#include + +struct PulseReader { + uint32_t* timer_buffer; + uint32_t* gpio_buffer; + uint32_t size; + uint32_t pos; + uint32_t timer_value; + uint32_t gpio_value; + uint32_t gpio_mask; + uint32_t unit_multiplier; + uint32_t unit_divider; + uint32_t bit_time; + uint32_t dma_channel; + const GpioPin* gpio; + GpioPull pull; + LL_DMA_InitTypeDef dma_config_timer; + LL_DMA_InitTypeDef dma_config_gpio; +}; #define GPIO_PIN_MAP(pin, prefix) \ (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index be0ad7012..08056a0ac 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -3,10 +3,6 @@ #include #include #include -#include -#include -#include -#include #include @@ -28,23 +24,8 @@ typedef enum { PulseReaderUnitMicrosecond, } PulseReaderUnit; -typedef struct { - uint32_t* timer_buffer; - uint32_t* gpio_buffer; - uint32_t size; - uint32_t pos; - uint32_t timer_value; - uint32_t gpio_value; - uint32_t gpio_mask; - uint32_t unit_multiplier; - uint32_t unit_divider; - uint32_t bit_time; - uint32_t dma_channel; - const GpioPin* gpio; - GpioPull pull; - LL_DMA_InitTypeDef dma_config_timer; - LL_DMA_InitTypeDef dma_config_gpio; -} PulseReader; +/* using an anonymous type */ +typedef struct PulseReader PulseReader; /** Allocate a PulseReader object * From bc80ddd0a7c13a81c190b84c2b3815ed21969439 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 22:36:30 +0100 Subject: [PATCH 029/216] digital_signal/pulse_reader: allow parameters for free to be NULL --- lib/digital_signal/digital_signal.c | 8 ++++++++ lib/pulse_reader/pulse_reader.c | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 12b543273..ae87a09e4 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -71,6 +71,10 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { void digital_signal_free(DigitalSignal* signal) { furi_assert(signal); + if(!signal) { + return; + } + free(signal->edge_timings); free(signal->reload_reg_buff); free(signal->internals); @@ -298,6 +302,10 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { void digital_sequence_free(DigitalSequence* sequence) { furi_assert(sequence); + if(!sequence) { + return; + } + free(sequence->signals); free(sequence->sequence); free(sequence); diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 84ce2ff23..c8d0e3ff7 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -117,6 +117,12 @@ void pulse_reader_set_pull(PulseReader* signal, GpioPull pull) { } void pulse_reader_free(PulseReader* signal) { + furi_assert(signal); + + if(!signal) { + return; + } + free(signal->timer_buffer); free(signal->gpio_buffer); free(signal); From cd082c9d90911c3d65f9b98f41eba25445cb2420 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 10:50:55 +0100 Subject: [PATCH 030/216] digital_signal: show unoptimized and optimized code for digital_signal_update_dma() next to each other --- lib/digital_signal/digital_signal.c | 62 ++++++++++++++++++----------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index ae87a09e4..1be81f135 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -342,36 +342,42 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { sequence->sequence[sequence->sequence_used++] = signal_index; } -#if defined(DIGITAL_SIGNAL_PORTABLE_CODE) +bool digital_signal_optimization = true; -static void digital_signal_update_dma(DigitalSignal* signal) { - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->internals->gpio_buff); +static void digital_signal_update_dma_c(DigitalSignal* signal) { + /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ + while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { + } + + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->internals->reload_reg_entries); - - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->internals->gpio_buff); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); } -#else - -static void digital_signal_update_dma(DigitalSignal* signal) { +static void digital_signal_update_dma_asm(DigitalSignal* signal) { volatile uint32_t dma1_data[] = { - /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), - /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, - /* R8 */ 2, - /* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR), - /* R10 */ (uint32_t)signal->internals->gpio_buff, - /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; + /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* base address of DMA channel 1 */ + /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* CCR value to write first */ + /* R8 */ 2, /* CNDTR to write */ + /* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR), /* CPAR to write */ + /* R10 */ (uint32_t)signal->internals->gpio_buff, /* CMAR to write */ + /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; /* and CCR again to write after finished */ volatile uint32_t dma2_data[] = { - /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), - /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, - /* R2 */ (uint32_t)signal->internals->reload_reg_entries, - /* R3 */ (uint32_t) & (TIM2->ARR), - /* R4 */ (uint32_t)signal->reload_reg_buff, - /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; + /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* base address of DMA channel 2 */ + /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ + /* R2 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ + /* R3 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ + /* R4 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ + /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; /* and CCR again to write after finished */ /* hurry when setting up next transfer */ asm volatile( @@ -389,10 +395,12 @@ static void digital_signal_update_dma(DigitalSignal* signal) { "CMP r12, #0\n\t" "BNE loop\n\t" + /* no transfers left, the DMA has finished. now quickly re-enable with new settings + the next 4 instructions are the critical part */ "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ - "STR r11, [r6, #0]\n\t" /* enable channel again */ + "STR r11, [r6, #0]\n\t" /* enable channel again by writing CCR */ "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ - "STR r5, [r0, #0]\n\t" /* enable channel again */ + "STR r5, [r0, #0]\n\t" /* enable channel again by writing CCR */ "POP {r0-r12}\n\t" @@ -405,7 +413,13 @@ static void digital_signal_update_dma(DigitalSignal* signal) { LL_DMA_ClearFlag_TC2(DMA1); } -#endif +void digital_signal_update_dma(DigitalSignal* signal) { + if(digital_signal_optimization) { + digital_signal_update_dma_asm(signal); + } else { + digital_signal_update_dma_c(signal); + } +} static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { furi_assert(sequence); From 064a34e681235587135ba083c47e046eb1823061 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 12:21:43 +0100 Subject: [PATCH 031/216] pulse_reader: further optimize assembly code --- lib/digital_signal/digital_signal.c | 37 +++++++++++++---------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 1be81f135..073a69eb8 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -363,7 +363,17 @@ static void digital_signal_update_dma_c(DigitalSignal* signal) { } static void digital_signal_update_dma_asm(DigitalSignal* signal) { - volatile uint32_t dma1_data[] = { + /* this is an "already-prepared" buffer of all DMA channel configs to write */ + const volatile uint32_t dma_data[] = { + /* DMA channel 2 data */ + /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* base address of DMA channel 2 */ + /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ + /* R2 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ + /* R3 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ + /* R4 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ + /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN, /* and CCR again to write after finished */ + + /* DMA channel 1 data */ /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* base address of DMA channel 1 */ /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* CCR value to write first */ /* R8 */ 2, /* CNDTR to write */ @@ -371,31 +381,19 @@ static void digital_signal_update_dma_asm(DigitalSignal* signal) { /* R10 */ (uint32_t)signal->internals->gpio_buff, /* CMAR to write */ /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; /* and CCR again to write after finished */ - volatile uint32_t dma2_data[] = { - /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* base address of DMA channel 2 */ - /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ - /* R2 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ - /* R3 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ - /* R4 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ - /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN}; /* and CCR again to write after finished */ - - /* hurry when setting up next transfer */ + /* now wait for the DMA finishing and instantly reconfigure it with as few instructions as possible */ asm volatile( "\t" - "MOV r6, %[data1]\n\t" - "MOV r7, %[data2]\n\t" - "PUSH {r0-r12}\n\t" - "LDM r7, {r0-r5}\n\t" /* prepare registers with values to write into DMA config */ - "LDM r6, {r6-r11}\n\t" + "LDM %[data], {r0-r11}\n\t" /* prepare registers with values to write into DMA config */ - "loop:\n\t" + "wait_for_dma_finished:\n\t" "LDR r12, [r0, #4]\n\t" /* read DMA_CNDTRx to get remaining transfers */ "CMP r12, #0\n\t" - "BNE loop\n\t" + "BNE wait_for_dma_finished\n\t" - /* no transfers left, the DMA has finished. now quickly re-enable with new settings + /* no transfers left, the DMA has finished. now quickly re-enable with new settings. the next 4 instructions are the critical part */ "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ "STR r11, [r6, #0]\n\t" /* enable channel again by writing CCR */ @@ -406,8 +404,7 @@ static void digital_signal_update_dma_asm(DigitalSignal* signal) { : /* no outputs*/ : /* inputs */ - [data1] "r"(dma1_data), [data2] "r"(dma2_data) - : "r6", "r7"); + [data] "r"(dma_data)); LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC2(DMA1); From 17f7f0e637e2aa3714c8a491700bcb81ab2cab16 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 16:18:55 +0100 Subject: [PATCH 032/216] digital_signal: reduce code complexity of digital_signal_update_dma() by only reconfiguring DMA2 --- lib/digital_signal/digital_signal.c | 53 +++++++++-------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 073a69eb8..4772b654f 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -350,64 +350,45 @@ static void digital_signal_update_dma_c(DigitalSignal* signal) { } LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->internals->reload_reg_entries); + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->internals->gpio_buff); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); - - LL_DMA_ClearFlag_TC1(DMA1); - LL_DMA_ClearFlag_TC2(DMA1); } static void digital_signal_update_dma_asm(DigitalSignal* signal) { - /* this is an "already-prepared" buffer of all DMA channel configs to write */ + /* this is an "already-prepared" buffer of DMA channel 2 config to write */ const volatile uint32_t dma_data[] = { - /* DMA channel 2 data */ + /* base addresses of DMA channel register */ /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* base address of DMA channel 2 */ - /* R1 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ - /* R2 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ - /* R3 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ - /* R4 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ - /* R5 */ DMA1_Channel2->CCR | DMA_CCR_EN, /* and CCR again to write after finished */ - - /* DMA channel 1 data */ - /* R6 */ (uint32_t) & (DMA1_Channel1->CCR), /* base address of DMA channel 1 */ - /* R7 */ DMA1_Channel1->CCR & ~DMA_CCR_EN, /* CCR value to write first */ - /* R8 */ 2, /* CNDTR to write */ - /* R9 */ (uint32_t) & (signal->internals->gpio->port->BSRR), /* CPAR to write */ - /* R10 */ (uint32_t)signal->internals->gpio_buff, /* CMAR to write */ - /* R11 */ DMA1_Channel1->CCR | DMA_CCR_EN}; /* and CCR again to write after finished */ + /* R1 */ DMA1_Channel2->CCR | DMA_CCR_EN, /* CCR to write after finished */ + /* R2 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ + /* R3 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ + /* R4 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ + /* R5 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ + }; /* now wait for the DMA finishing and instantly reconfigure it with as few instructions as possible */ asm volatile( "\t" - "PUSH {r0-r12}\n\t" + "PUSH {r0-r6}\n\t" - "LDM %[data], {r0-r11}\n\t" /* prepare registers with values to write into DMA config */ + "LDM %[data], {r0-r5}\n\t" /* prepare registers with values to write into DMA config */ "wait_for_dma_finished:\n\t" - "LDR r12, [r0, #4]\n\t" /* read DMA_CNDTRx to get remaining transfers */ - "CMP r12, #0\n\t" + "LDR r6, [r0, #4]\n\t" /* read DMA_CNDTRx of DMA1 chan 2 to get remaining transfers */ + "CMP r6, #0\n\t" "BNE wait_for_dma_finished\n\t" /* no transfers left, the DMA has finished. now quickly re-enable with new settings. - the next 4 instructions are the critical part */ - "STM r6, {r7-r10}\n\t" /* disable channel and set up new parameters */ - "STR r11, [r6, #0]\n\t" /* enable channel again by writing CCR */ - "STM r0, {r1-r4}\n\t" /* disable channel and set up new parameters */ - "STR r5, [r0, #0]\n\t" /* enable channel again by writing CCR */ + these next 2 instructions are the critical part */ + "STM r0, {r2-r5}\n\t" /* disable channel and set up new parameters */ + "STR r1, [r0, #0]\n\t" /* enable channel again by writing CCR */ - "POP {r0-r12}\n\t" + "POP {r0-r6}\n\t" : /* no outputs*/ : /* inputs */ [data] "r"(dma_data)); - - LL_DMA_ClearFlag_TC1(DMA1); - LL_DMA_ClearFlag_TC2(DMA1); } void digital_signal_update_dma(DigitalSignal* signal) { From 4c3a5e9c125e61bc05f44903f0bbcf704675fa1a Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 16:34:52 +0100 Subject: [PATCH 033/216] digital_signal: remove assembly code, limiting the performance but increasing portability --- lib/digital_signal/digital_signal.c | 54 ++++------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 4772b654f..f420652f4 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -342,63 +342,21 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { sequence->sequence[sequence->sequence_used++] = signal_index; } -bool digital_signal_optimization = true; +static void digital_signal_update_dma(DigitalSignal* signal) { + /* keep them prepared in registers so there is less delay when writing */ + register volatile uint16_t len = signal->internals->reload_reg_entries; + register volatile uint32_t addr = (uint32_t)signal->reload_reg_buff; -static void digital_signal_update_dma_c(DigitalSignal* signal) { /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { } LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->internals->reload_reg_entries); - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, len); + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, addr); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); } -static void digital_signal_update_dma_asm(DigitalSignal* signal) { - /* this is an "already-prepared" buffer of DMA channel 2 config to write */ - const volatile uint32_t dma_data[] = { - /* base addresses of DMA channel register */ - /* R0 */ (uint32_t) & (DMA1_Channel2->CCR), /* base address of DMA channel 2 */ - /* R1 */ DMA1_Channel2->CCR | DMA_CCR_EN, /* CCR to write after finished */ - /* R2 */ DMA1_Channel2->CCR & ~DMA_CCR_EN, /* CCR value to write first */ - /* R3 */ (uint32_t)signal->internals->reload_reg_entries, /* CNDTR to write */ - /* R4 */ (uint32_t) & (TIM2->ARR), /* CPAR to write */ - /* R5 */ (uint32_t)signal->reload_reg_buff, /* CMAR to write */ - }; - - /* now wait for the DMA finishing and instantly reconfigure it with as few instructions as possible */ - asm volatile( - "\t" - "PUSH {r0-r6}\n\t" - - "LDM %[data], {r0-r5}\n\t" /* prepare registers with values to write into DMA config */ - - "wait_for_dma_finished:\n\t" - "LDR r6, [r0, #4]\n\t" /* read DMA_CNDTRx of DMA1 chan 2 to get remaining transfers */ - "CMP r6, #0\n\t" - "BNE wait_for_dma_finished\n\t" - - /* no transfers left, the DMA has finished. now quickly re-enable with new settings. - these next 2 instructions are the critical part */ - "STM r0, {r2-r5}\n\t" /* disable channel and set up new parameters */ - "STR r1, [r0, #0]\n\t" /* enable channel again by writing CCR */ - - "POP {r0-r6}\n\t" - - : /* no outputs*/ - : /* inputs */ - [data] "r"(dma_data)); -} - -void digital_signal_update_dma(DigitalSignal* signal) { - if(digital_signal_optimization) { - digital_signal_update_dma_asm(signal); - } else { - digital_signal_update_dma_c(signal); - } -} - static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { furi_assert(sequence); furi_assert(signal); From 7e42c9c3f0df43d683ed2002f7b0bb6b1d29df0c Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Tue, 3 Jan 2023 02:10:30 +0100 Subject: [PATCH 034/216] added recovery if the timer already expired --- lib/digital_signal/digital_signal.c | 50 +++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index f420652f4..e07235ece 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -1,6 +1,7 @@ #include "digital_signal.h" #include +#include #include #include @@ -17,6 +18,7 @@ struct DigitalSequence { uint8_t* sequence; const GpioPin* gpio; uint32_t send_time; + bool send_time_active; }; struct DigitalSignalInternals { @@ -31,7 +33,7 @@ struct DigitalSignalInternals { #define TAG "DigitalSignal" #define F_TIM (64000000.0) -#define T_TIM 1562 /* 15.625 ns *100 */ +#define T_TIM 1562 /* 15.625 ns *100 */ #define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { @@ -285,9 +287,12 @@ void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { sequence->sequence_size = size; sequence->sequence = malloc(sequence->sequence_size); sequence->send_time = 0; + sequence->send_time_active = false; } DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { + furi_assert(gpio); + DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); sequence->gpio = gpio; @@ -327,7 +332,10 @@ void digital_sequence_set_signal( } void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) { + furi_assert(sequence); + sequence->send_time = send_time; + sequence->send_time_active = true; } void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { @@ -344,23 +352,40 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { static void digital_signal_update_dma(DigitalSignal* signal) { /* keep them prepared in registers so there is less delay when writing */ + register bool restart_needed = false; register volatile uint16_t len = signal->internals->reload_reg_entries; register volatile uint32_t addr = (uint32_t)signal->reload_reg_buff; - /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ - while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { + /* first make sure it will still count down, else we will risk waiting infinitely */ + const uint32_t wait_ms = 10; + const uint32_t wait_ticks = wait_ms * 1000 * furi_hal_cortex_instructions_per_microsecond(); + uint16_t prev_remain = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); + uint32_t prev_timer = DWT->CYCCNT; + + while(prev_remain == LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { + if(DWT->CYCCNT - prev_timer > wait_ticks) { + restart_needed = true; + break; + } + } + + if(!restart_needed) { + /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ + while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { + } } LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, len); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, addr); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + if(restart_needed) { + LL_TIM_GenerateEvent_UPDATE(TIM2); + } } static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { - furi_assert(sequence); - furi_assert(signal); - /* the first iteration has to set up the whole machinery */ if(!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) { if(!digital_signal_setup_dma(signal)) { @@ -370,13 +395,9 @@ static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSigna digital_signal_setup_timer(); /* if the send time is specified, wait till the core timer passed beyond that time */ - if(sequence->send_time != 0) { - while(true) { - uint32_t delta = sequence->send_time - DWT->CYCCNT; - /* yeah, it's making use of underflows... */ - if(delta > 0x80000000) { - break; - } + if(sequence->send_time_active) { + sequence->send_time_active = false; + while(sequence->send_time - DWT->CYCCNT < 0x80000000) { } } digital_signal_start_timer(); @@ -389,6 +410,8 @@ static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSigna } DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { + furi_assert(sequence); + uint32_t edges = 0; for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { @@ -468,6 +491,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { } FURI_CRITICAL_EXIT(); + /* wait until last dma transaction was finished */ while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { } From 4f076485a31027f72f1b9affb0c3d370d5bac391 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Mon, 16 Jan 2023 10:49:01 +0100 Subject: [PATCH 035/216] digital_signal: fix memory leak --- lib/digital_signal/digital_signal.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index e07235ece..91f5b2173 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -292,7 +292,7 @@ void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { furi_assert(gpio); - + DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); sequence->gpio = gpio; @@ -313,6 +313,7 @@ void digital_sequence_free(DigitalSequence* sequence) { free(sequence->signals); free(sequence->sequence); + free(sequence->signals_prolonged); free(sequence); } @@ -333,7 +334,7 @@ void digital_sequence_set_signal( void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) { furi_assert(sequence); - + sequence->send_time = send_time; sequence->send_time_active = true; } @@ -365,7 +366,7 @@ static void digital_signal_update_dma(DigitalSignal* signal) { while(prev_remain == LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { if(DWT->CYCCNT - prev_timer > wait_ticks) { restart_needed = true; - break; + break; } } @@ -411,7 +412,7 @@ static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSigna DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { furi_assert(sequence); - + uint32_t edges = 0; for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { From e2b77fcfb2918b58645491b0da3006d6199a385d Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Mon, 16 Jan 2023 18:09:35 +0100 Subject: [PATCH 036/216] digital_signal: keep lock until all DMA transfers have finished --- lib/digital_signal/digital_signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 91f5b2173..474e840a0 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -490,7 +490,6 @@ bool digital_sequence_send(DigitalSequence* sequence) { break; } } - FURI_CRITICAL_EXIT(); /* wait until last dma transaction was finished */ while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { @@ -498,6 +497,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { digital_signal_stop_timer(); digital_signal_stop_dma(); + FURI_CRITICAL_EXIT(); /* undo previously prolonged edges */ for(uint32_t pos = 0; pos < sequence->signals_size; pos++) { From 826e4d1eda4de0d8f224ce4052db30eb8da98b4e Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 1 Feb 2023 23:25:23 +0100 Subject: [PATCH 037/216] DigitalSequence: fix issues with concatenation of same levels and spurious bit flips --- lib/digital_signal/digital_signal.c | 282 +++++++++++++++++++--------- 1 file changed, 195 insertions(+), 87 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 474e840a0..4ceca2ead 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -8,17 +8,26 @@ #include #include + +struct ReloadBuffers { + uint32_t** buffers; /* pointers to the shadow buffers, either one or two. NULL if none */ + uint32_t count; /* number of allocated buffers, 0, 1 or 2 */ + uint32_t size; /* maximum entry count of a single buffer */ + uint32_t current; /* current buffer index, the other one is most likely being used */ + uint32_t entries; /* entries in the current buffer */ +}; + struct DigitalSequence { uint8_t signals_size; bool bake; uint32_t sequence_used; uint32_t sequence_size; DigitalSignal** signals; - bool* signals_prolonged; uint8_t* sequence; const GpioPin* gpio; uint32_t send_time; bool send_time_active; + struct ReloadBuffers* reload; }; struct DigitalSignalInternals { @@ -28,6 +37,7 @@ struct DigitalSignalInternals { const GpioPin* gpio; LL_DMA_InitTypeDef dma_config_gpio; LL_DMA_InitTypeDef dma_config_timer; + struct ReloadBuffers* reload; }; #define TAG "DigitalSignal" @@ -45,27 +55,30 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->internals = malloc(sizeof(DigitalSignalInternals)); - signal->internals->reload_reg_entries = 0; - signal->internals->reload_reg_remainder = 0; - signal->internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - signal->internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; - signal->internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->internals->dma_config_gpio.NbData = 2; - signal->internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + DigitalSignalInternals* internals = signal->internals; + internals->reload = NULL; + internals->reload_reg_entries = 0; + internals->reload_reg_remainder = 0; - signal->internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - signal->internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - signal->internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; - signal->internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - signal->internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - signal->internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - signal->internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - signal->internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - signal->internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; + internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + internals->dma_config_gpio.NbData = 2; + internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -79,6 +92,12 @@ void digital_signal_free(DigitalSignal* signal) { free(signal->edge_timings); free(signal->reload_reg_buff); + if(signal->internals->reload) { + if(signal->internals->reload->buffers) { + free(signal->internals->reload->buffers); + } + free(signal->internals->reload); + } free(signal->internals); free(signal); } @@ -164,33 +183,55 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { void digital_signal_prepare_arr(DigitalSignal* signal) { furi_assert(signal); + DigitalSignalInternals* internals = signal->internals; + /* set up signal polarities */ - if(signal->internals->gpio) { - uint32_t bit_set = signal->internals->gpio->pin; - uint32_t bit_reset = signal->internals->gpio->pin << 16; + if(internals->gpio) { + uint32_t bit_set = internals->gpio->pin; + uint32_t bit_reset = internals->gpio->pin << 16; + +#ifdef DEBUG_OUTPUT + bit_set |= gpio_ext_pb3.pin; + bit_reset |= gpio_ext_pb3.pin << 16; +#endif if(signal->start_level) { - signal->internals->gpio_buff[0] = bit_set; - signal->internals->gpio_buff[1] = bit_reset; + internals->gpio_buff[0] = bit_set; + internals->gpio_buff[1] = bit_reset; } else { - signal->internals->gpio_buff[0] = bit_reset; - signal->internals->gpio_buff[1] = bit_set; + internals->gpio_buff[0] = bit_reset; + internals->gpio_buff[1] = bit_set; } } /* set up edge timings */ - signal->internals->reload_reg_entries = 0; + internals->reload_reg_entries = 0; for(size_t pos = 0; pos < signal->edge_cnt; pos++) { - uint32_t pulse_duration = - signal->edge_timings[pos] + signal->internals->reload_reg_remainder; + uint32_t pulse_duration = signal->edge_timings[pos] + internals->reload_reg_remainder; uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; - signal->internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); + internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); if(pulse_ticks > 1) { - signal->reload_reg_buff[signal->internals->reload_reg_entries++] = pulse_ticks - 1; + signal->reload_reg_buff[internals->reload_reg_entries++] = pulse_ticks - 1; } } + + /* in case there are no shadow buffers defined, allocate and use the precalced data */ + if(!internals->reload || !internals->reload->count) { + if(internals->reload) { + free(internals->reload); + } + internals->reload = malloc(sizeof(struct ReloadBuffers)); + internals->reload->count = 1; + internals->reload->size = signal->edges_max_cnt; + internals->reload->buffers = malloc(sizeof(uint32_t*)); + internals->reload->buffers[0] = malloc(internals->reload->size * sizeof(uint32_t)); + memcpy( + internals->reload->buffers[0], + signal->reload_reg_buff, + internals->reload_reg_entries * sizeof(uint32_t)); + } } static void digital_signal_stop_dma() { @@ -202,32 +243,8 @@ static void digital_signal_stop_dma() { static void digital_signal_stop_timer() { LL_TIM_DisableCounter(TIM2); - LL_TIM_SetCounter(TIM2, 0); -} - -static bool digital_signal_setup_dma(DigitalSignal* signal) { - furi_assert(signal); - - if(!signal->internals->reload_reg_entries) { - return false; - } - - signal->internals->dma_config_gpio.MemoryOrM2MDstAddress = - (uint32_t)signal->internals->gpio_buff; - signal->internals->dma_config_gpio.PeriphOrM2MSrcAddress = - (uint32_t) & (signal->internals->gpio->port->BSRR); - signal->internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - signal->internals->dma_config_timer.NbData = signal->internals->reload_reg_entries; - - /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->internals->dma_config_gpio); - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->internals->dma_config_timer); - - /* enable both DMA channels */ - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - - return true; + LL_TIM_DisableUpdateEvent(TIM2); + LL_TIM_DisableDMAReq_UPDATE(TIM2); } static void digital_signal_setup_timer() { @@ -236,15 +253,45 @@ static void digital_signal_setup_timer() { LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); - LL_TIM_SetAutoReload(TIM2, 10); + LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableUpdateEvent(TIM2); - LL_TIM_EnableDMAReq_UPDATE(TIM2); } static void digital_signal_start_timer() { - LL_TIM_GenerateEvent_UPDATE(TIM2); LL_TIM_EnableCounter(TIM2); + LL_TIM_EnableUpdateEvent(TIM2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); + LL_TIM_GenerateEvent_UPDATE(TIM2); +} + +static bool digital_signal_setup_dma(DigitalSignal* signal) { + furi_assert(signal); + DigitalSignalInternals* internals = signal->internals; + + uint32_t buffer_entries = internals->reload->entries; + if(!buffer_entries || !internals->reload || !internals->reload->buffers) { + return false; + } + digital_signal_stop_dma(); + + internals->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)internals->gpio_buff; + internals->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (internals->gpio->port->BSRR); + internals->dma_config_timer.MemoryOrM2MDstAddress = + (uint32_t)internals->reload->buffers[internals->reload->current]; + internals->dma_config_timer.NbData = buffer_entries; + + /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &internals->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &internals->dma_config_timer); + + /* enable both DMA channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + /* buffer is used now by DMA, skip to next */ + internals->reload->current = (internals->reload->current + 1) % internals->reload->count; + + return true; } void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { @@ -279,7 +326,6 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { sequence->signals_size = size; sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); - sequence->signals_prolonged = malloc(sequence->signals_size * sizeof(bool)); } void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { @@ -298,6 +344,13 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { sequence->gpio = gpio; sequence->bake = false; + sequence->reload = malloc(sizeof(struct ReloadBuffers)); + sequence->reload->count = 2; + sequence->reload->size = 512; + sequence->reload->buffers = malloc(sizeof(uint32_t*)); + sequence->reload->buffers[0] = malloc(sequence->reload->size * sizeof(uint32_t)); + sequence->reload->buffers[1] = malloc(sequence->reload->size * sizeof(uint32_t)); + digital_sequence_alloc_signals(sequence, 32); digital_sequence_alloc_sequence(sequence, size); @@ -311,9 +364,17 @@ void digital_sequence_free(DigitalSequence* sequence) { return; } + /* de-assign the shared reload buffer */ + for(int pos = 0; pos < sequence->signals_size; pos++) { + if(sequence->signals[pos]) { + sequence->signals[pos]->internals->reload = NULL; + } + } + free(sequence->signals); free(sequence->sequence); - free(sequence->signals_prolonged); + free(sequence->reload->buffers); + free(sequence->reload); free(sequence); } @@ -325,10 +386,38 @@ void digital_sequence_set_signal( furi_assert(signal); furi_assert(signal_index < sequence->signals_size); + /* if there is already a signal, unassign the shared reload buffer */ + if(sequence->signals[signal_index]) { + sequence->signals[signal_index]->internals->reload = NULL; + } + sequence->signals[signal_index] = signal; signal->internals->gpio = sequence->gpio; signal->internals->reload_reg_remainder = 0; + /* free the original reload buffer */ + if(signal->internals->reload) { + if(signal->internals->reload->buffers) { + for(uint32_t pos = 0; pos < signal->internals->reload->count; pos++) { + free(signal->internals->reload->buffers[pos]); + } + free(signal->internals->reload->buffers); + } + free(signal->internals->reload); + } + + /* assign the sequence's shared reload buffer */ + signal->internals->reload = sequence->reload; + + /* ensure it is big enough and reallocate if not */ + if(sequence->reload->size < signal->edges_max_cnt) { + free(sequence->reload->buffers); + + sequence->reload->size = signal->edges_max_cnt; + sequence->reload->buffers[0] = malloc(sequence->reload->size * sizeof(uint32_t)); + sequence->reload->buffers[1] = malloc(sequence->reload->size * sizeof(uint32_t)); + } + digital_signal_prepare_arr(signal); } @@ -352,10 +441,11 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { } static void digital_signal_update_dma(DigitalSignal* signal) { + struct ReloadBuffers* reload = signal->internals->reload; /* keep them prepared in registers so there is less delay when writing */ register bool restart_needed = false; - register volatile uint16_t len = signal->internals->reload_reg_entries; - register volatile uint32_t addr = (uint32_t)signal->reload_reg_buff; + register volatile uint16_t len = reload->entries; + register volatile uint32_t addr = (uint32_t)reload->buffers[reload->current]; /* first make sure it will still count down, else we will risk waiting infinitely */ const uint32_t wait_ms = 10; @@ -374,6 +464,8 @@ static void digital_signal_update_dma(DigitalSignal* signal) { /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { } + } else { + FURI_LOG_D(TAG, "digital_sequence_send_signal: DMA hung, restart needed"); } LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); @@ -384,6 +476,8 @@ static void digital_signal_update_dma(DigitalSignal* signal) { if(restart_needed) { LL_TIM_GenerateEvent_UPDATE(TIM2); } + + reload->current = (reload->current + 1) % reload->count; } static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { @@ -437,7 +531,12 @@ DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { bool digital_sequence_send(DigitalSequence* sequence) { furi_assert(sequence); + struct ReloadBuffers* reload = sequence->reload; + furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#ifdef DEBUG_OUTPUT + furi_hal_gpio_init(&gpio_ext_pb3, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#endif if(sequence->bake) { DigitalSignal* sig = digital_sequence_bake(sequence); @@ -450,9 +549,16 @@ bool digital_sequence_send(DigitalSequence* sequence) { int32_t remainder = 0; FURI_CRITICAL_ENTER(); + bool traded_first = false; + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { uint8_t signal_index = sequence->sequence[pos]; DigitalSignal* sig = sequence->signals[signal_index]; + DigitalSignal* sig_next = NULL; + + if(pos + 1 < sequence->sequence_used) { + sig_next = sequence->signals[sequence->sequence[pos + 1]]; + } if(!sig) { FURI_LOG_D( @@ -463,27 +569,39 @@ bool digital_sequence_send(DigitalSequence* sequence) { break; } - /* when we are too late more than half a tick, make the first edge temporarily longer */ - bool needs_prolongation = false; + /* if the first edge is handled by prolonging the last pulse of the previous signal, skip it here */ + reload->entries = sig->edge_cnt - (traded_first ? 1 : 0); + memcpy( + reload->buffers[reload->current], + &sig->reload_reg_buff[traded_first ? 1 : 0], + reload->entries * sizeof(uint32_t)); + traded_first = false; + + /* when we are too late more than half a tick, make the first edge temporarily longer */ if(remainder >= T_TIM_DIV2) { remainder -= T_TIM; - needs_prolongation = true; + reload->buffers[reload->current][0] += 1; } /* update the total remainder */ remainder += sig->internals->reload_reg_remainder; - /* do we need to update the prolongation? */ - if(needs_prolongation != sequence->signals_prolonged[signal_index]) { - if(needs_prolongation) { - sig->edge_timings[0]++; - } else { - sig->edge_timings[0]--; + /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ + if(sig_next) { + /* beware, we do not want the level after the last edge, but the last level before that edge */ + bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); + + /* take from the next, add it to the first */ + if(end_level == sig_next->start_level) { + /* add the traded prolongation to the last pulse */ + reload->buffers[reload->current][reload->entries - 1] += + sig_next->reload_reg_buff[0]; + traded_first = true; } - sequence->signals_prolonged[signal_index] = needs_prolongation; } + /* transmit */ bool success = digital_sequence_send_signal(sequence, sig); if(!success) { @@ -499,16 +617,6 @@ bool digital_sequence_send(DigitalSequence* sequence) { digital_signal_stop_dma(); FURI_CRITICAL_EXIT(); - /* undo previously prolonged edges */ - for(uint32_t pos = 0; pos < sequence->signals_size; pos++) { - DigitalSignal* sig = sequence->signals[pos]; - - if(sig && sequence->signals_prolonged[pos]) { - sig->edge_timings[0]--; - sequence->signals_prolonged[pos] = false; - } - } - return true; } From 3cb1b1f6c17fe9da185a73584166c28c7eb6693c Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 4 Feb 2023 01:39:56 +0100 Subject: [PATCH 038/216] DigitalSignal: use cyclic DMA buffer for sequences --- lib/digital_signal/digital_signal.c | 435 +++++++++++++++------------- lib/digital_signal/digital_signal.h | 1 + 2 files changed, 234 insertions(+), 202 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 4ceca2ead..59278277c 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -8,13 +8,15 @@ #include #include +/* must be on bank B */ +#define DEBUG_OUTPUT gpio_ext_pb3 -struct ReloadBuffers { - uint32_t** buffers; /* pointers to the shadow buffers, either one or two. NULL if none */ - uint32_t count; /* number of allocated buffers, 0, 1 or 2 */ - uint32_t size; /* maximum entry count of a single buffer */ - uint32_t current; /* current buffer index, the other one is most likely being used */ - uint32_t entries; /* entries in the current buffer */ +struct ReloadBuffer { + uint32_t* buffer; /* DMA ringbuffer */ + uint32_t size; /* maximum entry count of the ring buffer */ + uint32_t write_pos; /* current buffer write index */ + uint32_t read_pos; /* current buffer read index */ + bool dma_active; }; struct DigitalSequence { @@ -27,17 +29,20 @@ struct DigitalSequence { const GpioPin* gpio; uint32_t send_time; bool send_time_active; - struct ReloadBuffers* reload; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; + uint32_t* gpio_buff; + struct ReloadBuffer* dma_buffer; }; struct DigitalSignalInternals { + uint64_t factor; uint32_t reload_reg_entries; uint32_t reload_reg_remainder; uint32_t gpio_buff[2]; const GpioPin* gpio; LL_DMA_InitTypeDef dma_config_gpio; LL_DMA_InitTypeDef dma_config_timer; - struct ReloadBuffers* reload; }; #define TAG "DigitalSignal" @@ -56,9 +61,8 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->internals = malloc(sizeof(DigitalSignalInternals)); DigitalSignalInternals* internals = signal->internals; - internals->reload = NULL; - internals->reload_reg_entries = 0; - internals->reload_reg_remainder = 0; + + internals->factor = 1024 * 1024; internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; @@ -92,12 +96,6 @@ void digital_signal_free(DigitalSignal* signal) { free(signal->edge_timings); free(signal->reload_reg_buff); - if(signal->internals->reload) { - if(signal->internals->reload->buffers) { - free(signal->internals->reload->buffers); - } - free(signal->internals->reload); - } free(signal->internals); free(signal); } @@ -191,8 +189,8 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { uint32_t bit_reset = internals->gpio->pin << 16; #ifdef DEBUG_OUTPUT - bit_set |= gpio_ext_pb3.pin; - bit_reset |= gpio_ext_pb3.pin << 16; + bit_set |= DEBUG_OUTPUT.pin; + bit_reset |= DEBUG_OUTPUT.pin << 16; #endif if(signal->start_level) { @@ -208,7 +206,17 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { internals->reload_reg_entries = 0; for(size_t pos = 0; pos < signal->edge_cnt; pos++) { - uint32_t pulse_duration = signal->edge_timings[pos] + internals->reload_reg_remainder; + uint32_t edge_scaled = (internals->factor * signal->edge_timings[pos]) / (1024 * 1024); + uint32_t pulse_duration = edge_scaled + internals->reload_reg_remainder; + if(pulse_duration < 10 || pulse_duration > 10000000) { + FURI_LOG_D( + TAG, + "[prepare] pulse_duration out of range: %lu = %lu * %llu", + pulse_duration, + signal->edge_timings[pos], + internals->factor); + pulse_duration = 100; + } uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); @@ -216,22 +224,6 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { signal->reload_reg_buff[internals->reload_reg_entries++] = pulse_ticks - 1; } } - - /* in case there are no shadow buffers defined, allocate and use the precalced data */ - if(!internals->reload || !internals->reload->count) { - if(internals->reload) { - free(internals->reload); - } - internals->reload = malloc(sizeof(struct ReloadBuffers)); - internals->reload->count = 1; - internals->reload->size = signal->edges_max_cnt; - internals->reload->buffers = malloc(sizeof(uint32_t*)); - internals->reload->buffers[0] = malloc(internals->reload->size * sizeof(uint32_t)); - memcpy( - internals->reload->buffers[0], - signal->reload_reg_buff, - internals->reload_reg_entries * sizeof(uint32_t)); - } } static void digital_signal_stop_dma() { @@ -268,17 +260,15 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) { furi_assert(signal); DigitalSignalInternals* internals = signal->internals; - uint32_t buffer_entries = internals->reload->entries; - if(!buffer_entries || !internals->reload || !internals->reload->buffers) { + if(!signal->internals->reload_reg_entries) { return false; } digital_signal_stop_dma(); internals->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)internals->gpio_buff; internals->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (internals->gpio->port->BSRR); - internals->dma_config_timer.MemoryOrM2MDstAddress = - (uint32_t)internals->reload->buffers[internals->reload->current]; - internals->dma_config_timer.NbData = buffer_entries; + internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; + internals->dma_config_timer.NbData = signal->internals->reload_reg_entries; /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &internals->dma_config_gpio); @@ -288,9 +278,6 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) { LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - /* buffer is used now by DMA, skip to next */ - internals->reload->current = (internals->reload->current + 1) % internals->reload->count; - return true; } @@ -323,12 +310,12 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { signal->edge_cnt--; } -void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { +static void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { sequence->signals_size = size; sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); } -void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { +static void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { sequence->sequence_used = 0; sequence->sequence_size = size; sequence->sequence = malloc(sequence->sequence_size); @@ -344,12 +331,31 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { sequence->gpio = gpio; sequence->bake = false; - sequence->reload = malloc(sizeof(struct ReloadBuffers)); - sequence->reload->count = 2; - sequence->reload->size = 512; - sequence->reload->buffers = malloc(sizeof(uint32_t*)); - sequence->reload->buffers[0] = malloc(sequence->reload->size * sizeof(uint32_t)); - sequence->reload->buffers[1] = malloc(sequence->reload->size * sizeof(uint32_t)); + sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer)); + sequence->dma_buffer->size = 32; + sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t)); + + sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + sequence->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + sequence->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + sequence->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + sequence->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + sequence->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + sequence->dma_config_gpio.NbData = 2; + sequence->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + sequence->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + sequence->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + sequence->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; + sequence->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + sequence->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + sequence->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + sequence->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + sequence->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + sequence->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)sequence->dma_buffer->buffer; + sequence->dma_config_timer.NbData = sequence->dma_buffer->size; + sequence->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + sequence->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; digital_sequence_alloc_signals(sequence, 32); digital_sequence_alloc_sequence(sequence, size); @@ -364,17 +370,10 @@ void digital_sequence_free(DigitalSequence* sequence) { return; } - /* de-assign the shared reload buffer */ - for(int pos = 0; pos < sequence->signals_size; pos++) { - if(sequence->signals[pos]) { - sequence->signals[pos]->internals->reload = NULL; - } - } - free(sequence->signals); free(sequence->sequence); - free(sequence->reload->buffers); - free(sequence->reload); + free(sequence->dma_buffer->buffer); + free(sequence->dma_buffer); free(sequence); } @@ -386,38 +385,10 @@ void digital_sequence_set_signal( furi_assert(signal); furi_assert(signal_index < sequence->signals_size); - /* if there is already a signal, unassign the shared reload buffer */ - if(sequence->signals[signal_index]) { - sequence->signals[signal_index]->internals->reload = NULL; - } - sequence->signals[signal_index] = signal; signal->internals->gpio = sequence->gpio; signal->internals->reload_reg_remainder = 0; - /* free the original reload buffer */ - if(signal->internals->reload) { - if(signal->internals->reload->buffers) { - for(uint32_t pos = 0; pos < signal->internals->reload->count; pos++) { - free(signal->internals->reload->buffers[pos]); - } - free(signal->internals->reload->buffers); - } - free(signal->internals->reload); - } - - /* assign the sequence's shared reload buffer */ - signal->internals->reload = sequence->reload; - - /* ensure it is big enough and reallocate if not */ - if(sequence->reload->size < signal->edges_max_cnt) { - free(sequence->reload->buffers); - - sequence->reload->size = signal->edges_max_cnt; - sequence->reload->buffers[0] = malloc(sequence->reload->size * sizeof(uint32_t)); - sequence->reload->buffers[1] = malloc(sequence->reload->size * sizeof(uint32_t)); - } - digital_signal_prepare_arr(signal); } @@ -440,71 +411,26 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { sequence->sequence[sequence->sequence_used++] = signal_index; } -static void digital_signal_update_dma(DigitalSignal* signal) { - struct ReloadBuffers* reload = signal->internals->reload; - /* keep them prepared in registers so there is less delay when writing */ - register bool restart_needed = false; - register volatile uint16_t len = reload->entries; - register volatile uint32_t addr = (uint32_t)reload->buffers[reload->current]; +static bool digital_sequence_setup_dma(DigitalSequence* sequence) { + furi_assert(sequence); - /* first make sure it will still count down, else we will risk waiting infinitely */ - const uint32_t wait_ms = 10; - const uint32_t wait_ticks = wait_ms * 1000 * furi_hal_cortex_instructions_per_microsecond(); - uint16_t prev_remain = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); - uint32_t prev_timer = DWT->CYCCNT; + digital_signal_stop_dma(); - while(prev_remain == LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { - if(DWT->CYCCNT - prev_timer > wait_ticks) { - restart_needed = true; - break; - } - } + sequence->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)sequence->gpio_buff; + sequence->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (sequence->gpio->port->BSRR); - if(!restart_needed) { - /* if transfer was already active, wait till DMA is done and the last timer ticks are running */ - while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { - } - } else { - FURI_LOG_D(TAG, "digital_sequence_send_signal: DMA hung, restart needed"); - } + /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &sequence->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &sequence->dma_config_timer); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, len); - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, addr); + /* enable both DMA channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - if(restart_needed) { - LL_TIM_GenerateEvent_UPDATE(TIM2); - } - - reload->current = (reload->current + 1) % reload->count; -} - -static bool digital_sequence_send_signal(DigitalSequence* sequence, DigitalSignal* signal) { - /* the first iteration has to set up the whole machinery */ - if(!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) { - if(!digital_signal_setup_dma(signal)) { - FURI_LOG_D(TAG, "digital_sequence_send_signal: Signal has no entries, aborting"); - return false; - } - digital_signal_setup_timer(); - - /* if the send time is specified, wait till the core timer passed beyond that time */ - if(sequence->send_time_active) { - sequence->send_time_active = false; - while(sequence->send_time - DWT->CYCCNT < 0x80000000) { - } - } - digital_signal_start_timer(); - } else { - /* configure next polarities and timings */ - digital_signal_update_dma(signal); - } - return true; } -DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { +static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { furi_assert(sequence); uint32_t edges = 0; @@ -528,14 +454,94 @@ DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { return ret; } +static void digital_sequence_update_pos(DigitalSequence* sequence) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + dma_buffer->read_pos = dma_buffer->size - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); +} + +static const uint32_t wait_ms = 10; +static const uint32_t wait_ticks = wait_ms * 1000 * 64; + +static void digital_sequence_finish(DigitalSequence* sequence) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + if(dma_buffer->dma_active) { + uint32_t prev_timer = DWT->CYCCNT; + uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + do { + uint32_t last_pos = dma_buffer->read_pos; + + digital_sequence_update_pos(sequence); + + /* we are finished, when the DMA transferred the 0xFFFFFFFF-timer which is the current write_pos */ + if(dma_buffer->read_pos == end_pos) { + break; + } + + if(last_pos != dma_buffer->read_pos) { + prev_timer = DWT->CYCCNT; + } + if(DWT->CYCCNT - prev_timer > wait_ticks) { + FURI_LOG_D( + TAG, + "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)", + wait_ms, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + } while(1); + } + + digital_signal_stop_timer(); + digital_signal_stop_dma(); +} + +static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t length) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + if(dma_buffer->dma_active) { + uint32_t prev_timer = DWT->CYCCNT; + uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + do { + uint32_t last_pos = dma_buffer->read_pos; + digital_sequence_update_pos(sequence); + + if(dma_buffer->read_pos != end_pos) { + break; + } + + if(last_pos != dma_buffer->read_pos) { + prev_timer = DWT->CYCCNT; + } + if(DWT->CYCCNT - prev_timer > wait_ticks) { + FURI_LOG_D( + TAG, + "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)", + wait_ms, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + } while(1); + } + + dma_buffer->buffer[dma_buffer->write_pos] = length; + dma_buffer->write_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + dma_buffer->buffer[dma_buffer->write_pos] = 0xFFFFFFFF; +} + bool digital_sequence_send(DigitalSequence* sequence) { furi_assert(sequence); - struct ReloadBuffers* reload = sequence->reload; + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); #ifdef DEBUG_OUTPUT - furi_hal_gpio_init(&gpio_ext_pb3, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_init(&DEBUG_OUTPUT, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); #endif if(sequence->bake) { @@ -547,74 +553,88 @@ bool digital_sequence_send(DigitalSequence* sequence) { } int32_t remainder = 0; - FURI_CRITICAL_ENTER(); - bool traded_first = false; - for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { - uint8_t signal_index = sequence->sequence[pos]; + FURI_CRITICAL_ENTER(); + + dma_buffer->dma_active = false; + dma_buffer->buffer[0] = 0xFFFFFFFF; + dma_buffer->read_pos = 0; + dma_buffer->write_pos = 0; + + for(uint32_t seq_pos = 0; seq_pos < sequence->sequence_used; seq_pos++) { + uint8_t signal_index = sequence->sequence[seq_pos]; DigitalSignal* sig = sequence->signals[signal_index]; - DigitalSignal* sig_next = NULL; + bool last_signal = ((seq_pos + 1) == sequence->sequence_used); - if(pos + 1 < sequence->sequence_used) { - sig_next = sequence->signals[sequence->sequence[pos + 1]]; + /* all signals are prepared and we can re-use the GPIO buffer from the fist signal */ + if(seq_pos == 0) { + sequence->gpio_buff = sig->internals->gpio_buff; } - if(!sig) { - FURI_LOG_D( - TAG, - "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", - signal_index, - pos); - break; - } - - /* if the first edge is handled by prolonging the last pulse of the previous signal, skip it here */ - reload->entries = sig->edge_cnt - (traded_first ? 1 : 0); - - memcpy( - reload->buffers[reload->current], - &sig->reload_reg_buff[traded_first ? 1 : 0], - reload->entries * sizeof(uint32_t)); - traded_first = false; - - /* when we are too late more than half a tick, make the first edge temporarily longer */ - if(remainder >= T_TIM_DIV2) { - remainder -= T_TIM; - reload->buffers[reload->current][0] += 1; - } - - /* update the total remainder */ - remainder += sig->internals->reload_reg_remainder; - - /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ - if(sig_next) { - /* beware, we do not want the level after the last edge, but the last level before that edge */ - bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); - - /* take from the next, add it to the first */ - if(end_level == sig_next->start_level) { - /* add the traded prolongation to the last pulse */ - reload->buffers[reload->current][reload->entries - 1] += - sig_next->reload_reg_buff[0]; - traded_first = true; + for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) { + if(traded_first) { + traded_first = false; + continue; } - } + uint32_t pulse_length = 0; + bool last_pulse = ((pulse_pos + 1) == sig->internals->reload_reg_entries); - /* transmit */ - bool success = digital_sequence_send_signal(sequence, sig); + pulse_length = sig->reload_reg_buff[pulse_pos]; - if(!success) { - break; + /* when we are too late more than half a tick, make the first edge temporarily longer */ + if(remainder >= T_TIM_DIV2) { + remainder -= T_TIM; + pulse_length += 1; + } + remainder += sig->internals->reload_reg_remainder; + + /* last pulse in that signal and have a next signal? */ + if(last_pulse) { + if((seq_pos + 1) < sequence->sequence_used) { + DigitalSignal* sig_next = sequence->signals[sequence->sequence[seq_pos + 1]]; + + /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ + /* beware, we do not want the level after the last edge, but the last level before that edge */ + bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); + + /* take from the next, add it to the current if they have the same level */ + if(end_level == sig_next->start_level) { + pulse_length += sig_next->reload_reg_buff[0]; + traded_first = true; + } + } + } + + digital_sequence_queue_pulse(sequence, pulse_length); + + /* start transmission when buffer was filled enough */ + bool start_send = sequence->dma_buffer->write_pos >= (sequence->dma_buffer->size - 4); + + /* or it was the last pulse */ + if(last_pulse && last_signal) { + start_send = true; + } + + /* start transmission */ + if(start_send && !dma_buffer->dma_active) { + digital_sequence_setup_dma(sequence); + digital_signal_setup_timer(); + + /* if the send time is specified, wait till the core timer passed beyond that time */ + if(sequence->send_time_active) { + sequence->send_time_active = false; + while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + } + } + digital_signal_start_timer(); + dma_buffer->dma_active = true; + } } } /* wait until last dma transaction was finished */ - while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { - } - - digital_signal_stop_timer(); - digital_signal_stop_dma(); + digital_sequence_finish(sequence); FURI_CRITICAL_EXIT(); return true; @@ -625,3 +645,14 @@ void digital_sequence_clear(DigitalSequence* sequence) { sequence->sequence_used = 0; } + +void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor) { + for(uint32_t sig_pos = 0; sig_pos < sequence->signals_size; sig_pos++) { + DigitalSignal* signal = sequence->signals[sig_pos]; + + if(signal) { + signal->internals->factor = (uint32_t)(1024 * 1024 * factor); + digital_signal_prepare_arr(signal); + } + } +} diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 2cb107486..40afb1e41 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -61,6 +61,7 @@ void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index); bool digital_sequence_send(DigitalSequence* sequence); void digital_sequence_clear(DigitalSequence* sequence); +void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor); #ifdef __cplusplus } From 999c356fedc7ac459f2b4f8193b04392e8c80f71 Mon Sep 17 00:00:00 2001 From: Tiernan Messmer Date: Mon, 1 May 2023 12:29:58 +1000 Subject: [PATCH 039/216] update api_symbols.csv --- firmware/targets/f7/api_symbols.csv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 2edbdb16d..3e145d32f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,23.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -744,6 +744,7 @@ Function,-,digital_sequence_free,void,DigitalSequence* Function,-,digital_sequence_send,_Bool,DigitalSequence* Function,-,digital_sequence_set_sendtime,void,"DigitalSequence*, uint32_t" Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*" +Function,-,digital_sequence_timebase_correction,void,"DigitalSequence*, float" Function,-,digital_signal_add,void,"DigitalSignal*, uint32_t" Function,-,digital_signal_add_pulse,void,"DigitalSignal*, uint32_t, _Bool" Function,-,digital_signal_alloc,DigitalSignal*,uint32_t From 3a5d8e15ebf9df1eaa839963c51eb30ed6e06c21 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 21 Dec 2022 01:06:22 +0100 Subject: [PATCH 040/216] added unit test for pulse_reader --- applications/debug/unit_tests/nfc/nfc_test.c | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 54bdd5909..3b3a44431 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -1,10 +1,12 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -179,6 +181,153 @@ MU_TEST(nfc_digital_signal_test) { "NFC long digital signal test failed\r\n"); } +static bool nfc_test_pulse_reader_toggle( + uint32_t usec_low, + uint32_t usec_high, + uint32_t period_count, + uint32_t tolerance) { + furi_assert(nfc_test); + + bool success = false; + uint32_t pulses = 0; + const GpioPin* gpio_in = &gpio_ext_pa6; + const GpioPin* gpio_out = &gpio_ext_pa7; + PulseReader* reader = NULL; + + do { + reader = pulse_reader_alloc(gpio_in, 512); + + if(!reader) { + FURI_LOG_E(TAG, "failed to allocate pulse reader"); + break; + } + + /* use TIM1 to create a specific number of pulses with defined duty cycle + but first set the IO to high, so the low/high pulse can get detected */ + furi_hal_gpio_init(gpio_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(gpio_out, true); + + LL_TIM_DeInit(TIM1); + + LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetRepetitionCounter(TIM1, 0); + LL_TIM_SetClockDivision(TIM1, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM1); + + LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH1); + LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM2); + 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_EnableAllOutputs(TIM1); + + /* now calculate the TIM1 period and compare values */ + uint32_t freq_div = 64 * (usec_low + usec_high); + uint32_t prescaler = freq_div / 0x10000LU; + uint32_t period = freq_div / (prescaler + 1); + uint32_t compare = 64 * usec_low / (prescaler + 1); + + LL_TIM_SetPrescaler(TIM1, prescaler); + LL_TIM_SetAutoReload(TIM1, period - 1); + LL_TIM_SetCounter(TIM1, period - 1); + LL_TIM_OC_SetCompareCH1(TIM1, compare); + + /* timer is ready to launch, now start the pulse reader */ + pulse_reader_set_timebase(reader, PulseReaderUnitMicrosecond); + pulse_reader_start(reader); + + /* and quickly enable and switch over the GPIO to the generated signal */ + LL_TIM_EnableCounter(TIM1); + furi_hal_gpio_init_ex( + gpio_out, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn1TIM1); + + /* now it's time to parse the pulses received by the reader */ + uint32_t timer_pulses = period_count; + uint32_t prev_cnt = 0; + + while(timer_pulses > 0) { + /* whenever the counter gets reset, we went through a full period */ + uint32_t cur_cnt = LL_TIM_GetCounter(TIM1); + if(cur_cnt < prev_cnt) { + timer_pulses--; + } + prev_cnt = cur_cnt; + } + /* quickly halt the counter to keep a static signal */ + LL_TIM_DisableCounter(TIM1); + + do { + /* as all edges were sampled asynchronously, the timeout can be zero */ + uint32_t length = pulse_reader_receive(reader, 0); + + /* in the last pulse, we expect a "no edge" return value. if seen that, test succeeded. */ + if(pulses > period_count * 2) { + if(length != PULSE_READER_NO_EDGE) { + FURI_LOG_E( + TAG, + "last pulse expected to be PULSE_READER_NO_EDGE, but was %lu.", + length); + break; + } + success = true; + break; + } + + /* else we shall never see "no edge" or "lost edge" */ + if(length == PULSE_READER_NO_EDGE) { + FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_NO_EDGE", pulses); + break; + } + if(length == PULSE_READER_LOST_EDGE) { + FURI_LOG_E(TAG, "%lu. pulse not expected to be PULSE_READER_LOST_EDGE", pulses); + break; + } + + if(pulses > 0) { + /* throw away the first pulse, which is the 1->0 from the first start and will be irrelevant for our test */ + bool phase = ((pulses - 1) % 2) == 1; + uint32_t expected = phase ? usec_high : usec_low; + uint32_t deviation = abs((int32_t)length - (int32_t)expected); + + if(deviation > tolerance) { + FURI_LOG_E( + TAG, + "%lu. pulse expected %lu, but pulse was %lu.", + pulses, + expected, + length); + break; + } + } + pulses++; + } while(true); + } while(false); + + if(reader != NULL) { + pulse_reader_stop(reader); + pulse_reader_free(reader); + } + + LL_TIM_DeInit(TIM1); + furi_hal_gpio_init_simple(gpio_in, GpioModeAnalog); + furi_hal_gpio_init_simple(gpio_out, GpioModeAnalog); + + return success; +} + +MU_TEST(nfc_pulse_reader_test) { + mu_assert(nfc_test_pulse_reader_toggle(1500, 2500, 50, 10), "1 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(10000, 10000, 10, 10), "10 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(100000, 100000, 5, 50), "100 ms signal failed\r\n"); + mu_assert(nfc_test_pulse_reader_toggle(100, 900, 50, 10), "1 ms asymmetric signal failed\r\n"); + mu_assert( + nfc_test_pulse_reader_toggle(3333, 6666, 10, 10), "10 ms asymmetric signal failed\r\n"); + mu_assert( + nfc_test_pulse_reader_toggle(25000, 75000, 5, 10), "100 ms asymmetric signal failed\r\n"); +} + MU_TEST(mf_classic_dict_test) { MfClassicDict* instance = NULL; uint64_t key = 0; @@ -513,6 +662,7 @@ MU_TEST(mf_classic_4k_7b_file_test) { MU_TEST_SUITE(nfc) { nfc_test_alloc(); + MU_RUN_TEST(nfc_pulse_reader_test); MU_RUN_TEST(nfca_file_test); MU_RUN_TEST(mf_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); From 6a95f8010fd53ffd07ebe7899ba6ec65a87ba10b Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Wed, 28 Dec 2022 18:52:12 +0100 Subject: [PATCH 041/216] added support for ISO15693 (NfcV) emulation, added support for reading SLIX tags --- applications/main/nfc/nfc.c | 3 + .../main/nfc/scenes/nfc_scene_config.h | 5 + .../main/nfc/scenes/nfc_scene_emulate_nfcv.c | 149 +++ .../main/nfc/scenes/nfc_scene_extra_actions.c | 10 + .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 166 +++- .../nfc/scenes/nfc_scene_nfcv_key_input.c | 48 + .../main/nfc/scenes/nfc_scene_nfcv_menu.c | 63 ++ .../main/nfc/scenes/nfc_scene_nfcv_unlock.c | 155 +++ .../nfc/scenes/nfc_scene_nfcv_unlock_menu.c | 60 ++ applications/main/nfc/scenes/nfc_scene_read.c | 5 + applications/main/nfc/scenes/nfc_scene_rpc.c | 7 + .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 + lib/nfc/nfc_device.c | 359 ++++++- lib/nfc/nfc_device.h | 4 + lib/nfc/nfc_worker.c | 226 ++++- lib/nfc/nfc_worker.h | 7 + lib/nfc/nfc_worker_i.h | 2 + lib/nfc/protocols/nfcv.c | 885 ++++++++++++++++++ lib/nfc/protocols/nfcv.h | 213 +++++ lib/nfc/protocols/slix.c | 407 ++++++++ lib/nfc/protocols/slix.h | 46 + 21 files changed, 2795 insertions(+), 27 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c create mode 100644 lib/nfc/protocols/nfcv.c create mode 100644 lib/nfc/protocols/nfcv.h create mode 100644 lib/nfc/protocols/slix.c create mode 100644 lib/nfc/protocols/slix.h diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index 4540f5d9f..a70a52f57 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -290,6 +290,9 @@ int32_t nfc_app(void* p) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); DOLPHIN_DEED(DolphinDeedNfcEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); + DOLPHIN_DEED(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9da07dfd..8f1011e75 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -14,6 +14,11 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) +ADD_SCENE(nfc, nfcv_menu, NfcVMenu) +ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) +ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) +ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) +ADD_SCENE(nfc, emulate_nfcv, EmulateNfcV) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c b/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c new file mode 100644 index 000000000..e6fc60d86 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c @@ -0,0 +1,149 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (100) + +enum { + NfcSceneEmulateNfcVStateWidget, + NfcSceneEmulateNfcVStateTextBox, +}; + +bool nfc_emulate_nfcv_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + return true; +} + +void nfc_scene_emulate_nfcv_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_emulate_nfcv_textbox_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +// Add widget with device name or inform that data received +static void nfc_scene_emulate_nfcv_widget_config(Nfc* nfc, bool data_received) { + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); + widget_add_string_element( + widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating NfcV"); + if(strcmp(nfc->dev->dev_name, "")) { + furi_string_printf(info_str, "%s", nfc->dev->dev_name); + } else { + for(uint8_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(info_str, "%02X ", data->uid[i]); + } + } + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_nfcv_widget_callback, nfc); + } +} + +void nfc_scene_emulate_nfcv_on_enter(void* context) { + Nfc* nfc = context; + + // Setup Widget + nfc_scene_emulate_nfcv_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + furi_string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVEmulate, + &nfc->dev->dev_data, + nfc_emulate_nfcv_worker_callback, + nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_emulate_nfcv_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateNfcV); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerExit) { + // Add data button to widget if data is received for the first time + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_emulate_nfcv_widget_config(nfc, true); + } + if(strlen(nfcv_data->last_command) > 0) { + /* use the last n bytes from the log so there's enough space for the new log entry */ + size_t maxSize = + NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); + if(furi_string_size(nfc->text_box_store) >= maxSize) { + furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1)); + } + furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command); + furi_string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + + /* clear previously logged command */ + strcpy(nfcv_data->last_command, ""); + } + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateNfcVStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateNfcVStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneEmulateNfcVStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_emulate_nfcv_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 66aaf5a26..9560768a5 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -4,6 +4,7 @@ enum SubmenuIndex { SubmenuIndexReadCardType, SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, + SubmenuIndexNfcVUnlock, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { @@ -34,6 +35,12 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexMfUltralightUnlock, nfc_scene_extra_actions_submenu_callback, nfc); + submenu_add_item( + submenu, + "Unlock SLIX-L", + SubmenuIndexNfcVUnlock, + nfc_scene_extra_actions_submenu_callback, + nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); @@ -58,6 +65,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); consumed = true; + } else if(event.event == SubmenuIndexNfcVUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 92ad7b56e..88df6705c 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -7,6 +7,17 @@ void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType typ } } +uint32_t nfc_scene_nfc_data_info_get_key(uint8_t* data) { + uint32_t value = 0; + + for(uint32_t pos = 0; pos < 4; pos++) { + value <<= 8; + value |= data[pos]; + } + + return value; +} + void nfc_scene_nfc_data_info_on_enter(void* context) { Nfc* nfc = context; Widget* widget = nfc->widget; @@ -15,7 +26,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || - (protocol == NfcDeviceProtocolMifareClassic)) { + (protocol == NfcDeviceProtocolMifareClassic) || (protocol == NfcDeviceProtocolNfcV)) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); text_scroll_height = 52; @@ -41,19 +52,156 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + } else if(protocol == NfcDeviceProtocolNfcV) { + switch(dev_data->nfcv_data.sub_type) { + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "\e#ISO15693\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n"); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n"); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n"); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n"); + break; + default: + furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); + break; + } } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } // Set tag iso data - char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; - furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + if(protocol == NfcDeviceProtocolNfcV) { + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + + furi_string_cat_printf(temp_str, "UID:\n"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf(temp_str, "\n"); + + furi_string_cat_printf(temp_str, "DSFID: %02X\n", nfcv_data->dsfid); + furi_string_cat_printf(temp_str, "AFI: %02X\n", nfcv_data->afi); + furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); + furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); + furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + + furi_string_cat_printf( + temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size); + + int maxBlocks = nfcv_data->block_num; + if(maxBlocks > 32) { + maxBlocks = 32; + furi_string_cat_printf(temp_str, "(truncated to %d blocks)\n", maxBlocks); + } + + for(int block = 0; block < maxBlocks; block++) { + for(int pos = 0; pos < nfcv_data->block_size; pos++) { + furi_string_cat_printf( + temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]); + } + furi_string_cat_printf(temp_str, "\n"); + } + furi_string_cat_printf(temp_str, "\n"); + + switch(dev_data->nfcv_data.sub_type) { + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "Type: Plain\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "Type: SLIX\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf( + temp_str, + " Write %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "Type: SLIX2\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); + furi_string_cat_printf( + temp_str, + " Write %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); + furi_string_cat_printf( + temp_str, + " Privacy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); + furi_string_cat_printf( + temp_str, + " Destroy %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); + furi_string_cat_printf( + temp_str, + " EAS %08lX\n", + nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); + break; + default: + furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); + break; + } + } else { + char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; + furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + furi_string_cat_printf( + temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); } - furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); // Set application specific data if(protocol == NfcDeviceProtocolMifareDesfire) { @@ -139,6 +287,8 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(protocol == NfcDeviceProtocolMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + } else if(protocol == NfcDeviceProtocolNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c b/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c new file mode 100644 index 000000000..cc53c4dcb --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c @@ -0,0 +1,48 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_nfcv_key_input_byte_input_callback(void* context) { + Nfc* nfc = context; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; + + memcpy(data->key_privacy, nfc->byte_input_store, 4); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_nfcv_key_input_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter The Password In Hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_nfcv_key_input_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 4); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_nfcv_key_input_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_nfcv_key_input_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c new file mode 100644 index 000000000..b30495a05 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c @@ -0,0 +1,63 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, +}; + +void nfc_scene_nfcv_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcv_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatNfcV; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfcv_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c new file mode 100644 index 000000000..b52cc0caa --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c @@ -0,0 +1,155 @@ +#include "../nfc_i.h" +#include + +typedef enum { + NfcSceneNfcVUnlockStateIdle, + NfcSceneNfcVUnlockStateDetecting, + NfcSceneNfcVUnlockStateUnlocked, + NfcSceneNfcVUnlockStateAlreadyUnlocked, + NfcSceneNfcVUnlockStateNotSupportedCard, +} NfcSceneNfcVUnlockState; + +static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) { + Nfc* nfc = context; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; + + if(event == NfcWorkerEventNfcVPassKey) { + memcpy(data->key_privacy, nfc->byte_input_store, 4); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + } + return true; +} + +void nfc_scene_nfcv_unlock_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) { + FuriHalNfcDevData* nfc_data = &(nfc->dev->dev_data.nfc_data); + NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data); + + uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock); + if(curr_state != state) { + Popup* popup = nfc->popup; + if(state == NfcSceneNfcVUnlockStateDetecting) { + popup_reset(popup); + popup_set_text( + popup, "Put figurine on\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50); + } else if(state == NfcSceneNfcVUnlockStateUnlocked) { + popup_reset(popup); + + if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) { + nfc_text_store_set( + nfc, + "%s/SLIX_%02X%02X%02X%02X%02X%02X%02X%02X%s", + NFC_APP_FOLDER, + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7], + NFC_APP_EXTENSION); + + nfc->dev->format = NfcDeviceSaveFormatNfcV; + + if(nfc_device_save(nfc->dev, nfc->text_store)) { + popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop); + } else { + popup_set_header( + popup, "Unlocked but\nsave failed!", 94, 3, AlignCenter, AlignTop); + } + } else { + popup_set_header(popup, "Successfully\nunlocked", 94, 3, AlignCenter, AlignTop); + } + + notification_message(nfc->notifications, &sequence_single_vibro); + //notification_message(nfc->notifications, &sequence_success); + + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); + popup_set_timeout(popup, 1500); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + } else if(state == NfcSceneNfcVUnlockStateAlreadyUnlocked) { + popup_reset(popup); + + popup_set_header(popup, "Already\nUnlocked!", 94, 3, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); + popup_set_timeout(popup, 1500); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + } else if(state == NfcSceneNfcVUnlockStateNotSupportedCard) { + popup_reset(popup); + popup_set_header(popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop); + popup_set_text(popup, nfcv_data->error, 4, 22, AlignLeft, AlignTop); + popup_set_icon(popup, 73, 20, &I_DolphinCommon_56x48); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock, state); + } +} + +void nfc_scene_nfcv_unlock_on_enter(void* context) { + Nfc* nfc = context; + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVUnlockAndSave, + &nfc->dev->dev_data, + nfc_scene_nfcv_unlock_worker_callback, + nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_nfcv_unlock_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateUnlocked); + consumed = true; + } else if(event.event == NfcWorkerEventAborted) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateAlreadyUnlocked); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateNotSupportedCard); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneNfcVUnlockMenu); + } + return consumed; +} + +void nfc_scene_nfcv_unlock_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + nfc_blink_stop(nfc); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVUnlock, NfcSceneNfcVUnlockStateIdle); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c new file mode 100644 index 000000000..9c4c81fbd --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c @@ -0,0 +1,60 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexNfcVUnlockMenuManual, + SubmenuIndexNfcVUnlockMenuTonieBox, +}; + +void nfc_scene_nfcv_unlock_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcv_unlock_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu); + submenu_add_item( + submenu, + "Enter PWD Manually", + SubmenuIndexNfcVUnlockMenuManual, + nfc_scene_nfcv_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As TonieBox", + SubmenuIndexNfcVUnlockMenuTonieBox, + nfc_scene_nfcv_unlock_menu_submenu_callback, + nfc); + submenu_set_selected_item(submenu, state); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcv_unlock_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNfcVUnlockMenuManual) { + nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodManual; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexNfcVUnlockMenuTonieBox) { + nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodTonieBox; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu, event.event); + } + return consumed; +} + +void nfc_scene_nfcv_unlock_menu_on_exit(void* context) { + Nfc* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 938f2da67..c3f9f1334 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -68,6 +68,11 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; + } else if(event.event == NfcWorkerEventReadNfcV) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); // Set unlock password input to 0xFFFFFFFF only on fresh read diff --git a/applications/main/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c index 60d01a30d..d06ee7564 100644 --- a/applications/main/nfc/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc/scenes/nfc_scene_rpc.c @@ -55,6 +55,13 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { &nfc->dev->dev_data, nfc_scene_rpc_emulate_callback, nfc); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVEmulate, + &nfc->dev->dev_data, + nfc_scene_rpc_emulate_callback, + nfc); } else { nfc_worker_start( nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index ba1f96539..b7fc66995 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -116,6 +116,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 517913070..b925d651e 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -58,6 +58,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_ furi_string_set(format_string, "Mifare Classic"); } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { furi_string_set(format_string, "Mifare DESFire"); + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + furi_string_set(format_string, "ISO15693"); } else { furi_string_set(format_string, "Unknown"); } @@ -93,6 +95,11 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; return true; } + if(furi_string_start_with_str(format_string, "ISO15693")) { + dev->format = NfcDeviceSaveFormatNfcV; + dev->dev_data.protocol = NfcDeviceProtocolNfcV; + return true; + } return false; } @@ -650,7 +657,310 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -// Leave for backward compatibility +static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX specific data")) break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVData)); + + do { + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break; + if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_write_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVData)); + + do { + if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_read_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVData)); + + do { + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break; + if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_write_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVData)); + + do { + if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_read_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVData* data = &dev->dev_data.nfcv_data; + + do { + uint32_t temp_uint32 = 0; + uint8_t temp_uint8 = 0; + + if(!flipper_format_write_comment_cstr(file, "Data Storage Format Identifier")) break; + if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break; + if(!flipper_format_write_comment_cstr(file, "Application Family Identifier")) break; + if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break; + if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break; + temp_uint32 = data->block_num; + if(!flipper_format_write_comment_cstr(file, "Number of memory blocks, usually 0 to 256")) + break; + if(!flipper_format_write_uint32(file, "Block Count", &temp_uint32, 1)) break; + if(!flipper_format_write_comment_cstr(file, "Size of a single memory block, usually 4")) + break; + if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break; + if(!flipper_format_write_hex( + file, "Data Content", data->data, data->block_num * data->block_size)) + break; + if(!flipper_format_write_comment_cstr( + file, + "Subtype of this card (0 = ISO15693, 1 = SLIX, 2 = SLIX-S, 3 = SLIX-L, 4 = SLIX2)")) + break; + temp_uint8 = (uint8_t)data->sub_type; + if(!flipper_format_write_hex(file, "Subtype", &temp_uint8, 1)) break; + + switch(data->sub_type) { + case NfcVTypePlain: + if(!flipper_format_write_comment_cstr(file, "End of ISO15693 parameters")) break; + saved = true; + break; + case NfcVTypeSlix: + saved = nfc_device_save_slix_data(file, dev); + break; + case NfcVTypeSlixS: + saved = nfc_device_save_slix_s_data(file, dev); + break; + case NfcVTypeSlixL: + saved = nfc_device_save_slix_l_data(file, dev); + break; + case NfcVTypeSlix2: + saved = nfc_device_save_slix2_data(file, dev); + break; + } + } while(false); + + return saved; +} + +bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVData* data = &dev->dev_data.nfcv_data; + + memset(data, 0, sizeof(NfcVData)); + + do { + uint32_t temp_uint32 = 0; + uint8_t temp_value = 0; + + if(!flipper_format_read_hex(file, "DSFID", &(data->dsfid), 1)) break; + if(!flipper_format_read_hex(file, "AFI", &(data->afi), 1)) break; + if(!flipper_format_read_hex(file, "IC Reference", &(data->ic_ref), 1)) break; + if(!flipper_format_read_uint32(file, "Block Count", &temp_uint32, 1)) break; + data->block_num = temp_uint32; + if(!flipper_format_read_hex(file, "Block Size", &(data->block_size), 1)) break; + if(!flipper_format_read_hex( + file, "Data Content", data->data, data->block_num * data->block_size)) + break; + if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break; + data->sub_type = temp_value; + + switch(data->sub_type) { + case NfcVTypePlain: + parsed = true; + break; + case NfcVTypeSlix: + parsed = nfc_device_load_slix_data(file, dev); + break; + case NfcVTypeSlixS: + parsed = nfc_device_load_slix_s_data(file, dev); + break; + case NfcVTypeSlixL: + parsed = nfc_device_load_slix_l_data(file, dev); + break; + case NfcVTypeSlix2: + parsed = nfc_device_load_slix2_data(file, dev); + break; + } + } while(false); + + return parsed; +} + +static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + EmvData* data = &dev->dev_data.emv_data; + uint32_t data_temp = 0; + + do { + // Write Bank card specific data + if(!flipper_format_write_comment_cstr(file, "Bank card specific data")) break; + if(!flipper_format_write_hex(file, "AID", data->aid, data->aid_len)) break; + if(!flipper_format_write_string_cstr(file, "Name", data->name)) break; + if(!flipper_format_write_hex(file, "Number", data->number, data->number_len)) break; + if(data->exp_mon) { + uint8_t exp_data[2] = {data->exp_mon, data->exp_year}; + if(!flipper_format_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break; + } + if(data->country_code) { + data_temp = data->country_code; + if(!flipper_format_write_uint32(file, "Country code", &data_temp, 1)) break; + } + if(data->currency_code) { + data_temp = data->currency_code; + if(!flipper_format_write_uint32(file, "Currency code", &data_temp, 1)) break; + } + saved = true; + } while(false); + + return saved; +} + bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; EmvData* data = &dev->dev_data.emv_data; @@ -1069,23 +1379,32 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; // Write nfc device type if(!flipper_format_write_comment_cstr( - file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) + file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic or ISO15693")) break; nfc_device_prepare_format_string(dev, temp_str); if(!flipper_format_write_string(file, "Device type", temp_str)) break; - // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) - break; + // Write UID + if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break; if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; - // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; - if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + + if(dev->format != NfcDeviceSaveFormatNfcV) { + // Write ATQA, SAK + if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break; + // Save ATQA in MSB order for correct companion apps display + uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; + if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + } + // Save more data if necessary if(dev->format == NfcDeviceSaveFormatMifareUl) { if(!nfc_device_save_mifare_ul_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { if(!nfc_device_save_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + if(!nfc_device_save_nfcv_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatBankCard) { + if(!nfc_device_save_bank_card_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { // Save data if(!nfc_device_save_mifare_classic_data(file, dev)) break; @@ -1160,18 +1479,20 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!nfc_device_parse_format_string(dev, temp_str)) break; // Read and parse UID, ATQA and SAK if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; - if(!(data_cnt == 4 || data_cnt == 7)) break; + if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) break; data->uid_len = data_cnt; if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; - if(version == version_with_lsb_atqa) { - if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; - } else { - uint8_t atqa[2] = {}; - if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; - data->atqa[0] = atqa[1]; - data->atqa[1] = atqa[0]; + if(dev->format != NfcDeviceSaveFormatNfcV) { + if(version == version_with_lsb_atqa) { + if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; + } else { + uint8_t atqa[2] = {}; + if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; + data->atqa[0] = atqa[1]; + data->atqa[1] = atqa[0]; + } + if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; } - if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; // Load CUID uint8_t* cuid_start = data->uid; if(data->uid_len == 7) { @@ -1186,6 +1507,8 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!nfc_device_load_mifare_classic_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { if(!nfc_device_load_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + if(!nfc_device_load_nfcv_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatBankCard) { if(!nfc_device_load_bank_card_data(file, dev)) break; } diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index df37ec3df..20df4f891 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -31,6 +32,7 @@ typedef enum { NfcDeviceProtocolMifareUl, NfcDeviceProtocolMifareClassic, NfcDeviceProtocolMifareDesfire, + NfcDeviceProtocolNfcV } NfcProtocol; typedef enum { @@ -39,6 +41,7 @@ typedef enum { NfcDeviceSaveFormatMifareUl, NfcDeviceSaveFormatMifareClassic, NfcDeviceSaveFormatMifareDesfire, + NfcDeviceSaveFormatNfcV, } NfcDeviceSaveFormat; typedef struct { @@ -73,6 +76,7 @@ typedef struct { MfUltralightData mf_ul_data; MfClassicData mf_classic_data; MifareDesfireData mf_df_data; + NfcVData nfcv_data; }; FuriString* parsed_data; } NfcDeviceData; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 28a1f6827..28ce057fc 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -111,6 +111,12 @@ int32_t nfc_worker_task(void* context) { nfc_worker_mf_classic_dict_attack(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) { nfc_worker_analyze_reader(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVEmulate) { + nfc_worker_emulate_nfcv(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) { + nfc_worker_nfcv_unlock(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { + nfc_worker_nfcv_unlock(nfc_worker); } furi_hal_nfc_sleep(); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); @@ -118,6 +124,179 @@ int32_t nfc_worker_task(void* context) { return 0; } +static bool nfc_worker_read_nfcv_content(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + NfcVReader reader = {}; + + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + do { + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; + if(!nfcv_read_card(&reader, nfc_data, nfcv_data)) break; + + read_success = true; + } while(false); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + + return read_success; +} + +void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + FuriHalNfcTxRxContext tx_rx = {}; + uint8_t* key_data = nfcv_data->sub_data.slix.key_privacy; + uint32_t key = 0; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + furi_hal_nfc_sleep(); + + while((nfc_worker->state == NfcWorkerStateNfcVUnlock) || + (nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave)) { + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_ll_poll(); + if(furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollNfcv, FuriHalNfcBitrate26p48, FuriHalNfcBitrate26p48) != + FuriHalNfcReturnOk) { + break; + } + + furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER); + furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCV_POLLER); + furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); + furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV); + + furi_hal_console_printf("Detect presence\r\n"); + ReturnCode ret = slix_get_random(nfcv_data); + + if(ret == ERR_NONE) { + /* there is some chip, responding with a RAND */ + nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + furi_hal_console_printf(" Chip detected. In privacy?\r\n"); + ret = nfcv_inventory(NULL); + + if(ret == ERR_NONE) { + /* chip is also visible, so no action required, just save */ + if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { + NfcVReader reader = {}; + + if(!nfcv_read_card(&reader, &nfc_worker->dev_data->nfc_data, nfcv_data)) { + furi_hal_console_printf(" => failed, wait for chip to disappear.\r\n"); + snprintf(nfcv_data->error, sizeof(nfcv_data->error), "Read card\nfailed"); + nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context); + } else { + furi_hal_console_printf(" => success, wait for chip to disappear.\r\n"); + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + } + } else { + furi_hal_console_printf(" => success, wait for chip to disappear.\r\n"); + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + } + + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + + furi_hal_console_printf( + " => chip is already visible, wait for chip to disappear.\r\n"); + nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context); + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + + key_data[0] = 0; + key_data[1] = 0; + key_data[2] = 0; + key_data[3] = 0; + + } else { + /* chip is invisible, try to unlock */ + furi_hal_console_printf(" chip is invisible, unlocking\r\n"); + + if(nfcv_data->auth_method == NfcVAuthMethodManual) { + key |= key_data[0] << 24; + key |= key_data[1] << 16; + key |= key_data[2] << 8; + key |= key_data[3] << 0; + + ret = slix_unlock(nfcv_data, 4); + } else { + key = 0x7FFD6E5B; + key_data[0] = key >> 24; + key_data[1] = key >> 16; + key_data[2] = key >> 8; + key_data[3] = key >> 0; + ret = slix_unlock(nfcv_data, 4); + + if(ret != ERR_NONE) { + /* main key failed, trying second one */ + furi_hal_console_printf(" trying second key after resetting\r\n"); + + /* reset chip */ + furi_hal_nfc_ll_txrx_off(); + furi_delay_ms(20); + furi_hal_nfc_ll_txrx_on(); + + if(slix_get_random(nfcv_data) != ERR_NONE) { + furi_hal_console_printf(" reset failed\r\n"); + } + + key = 0x0F0F0F0F; + key_data[0] = key >> 24; + key_data[1] = key >> 16; + key_data[2] = key >> 8; + key_data[3] = key >> 0; + ret = slix_unlock(nfcv_data, 4); + } + } + if(ret != ERR_NONE) { + /* unlock failed */ + furi_hal_console_printf(" => failed, wait for chip to disappear.\r\n"); + snprintf( + nfcv_data->error, sizeof(nfcv_data->error), "Passwords not\naccepted"); + nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context); + + /* reset chip */ + furi_hal_nfc_ll_txrx_off(); + furi_delay_ms(20); + furi_hal_nfc_ll_txrx_on(); + + /* wait for disappearing */ + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + } + } + } else { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + } + + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_sleep(); + furi_delay_ms(100); + } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { bool read_success = false; MfUltralightReader reader = {}; @@ -260,6 +439,20 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t return card_read; } +static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(nfc_worker); + furi_assert(tx_rx); + + bool card_read = false; + furi_hal_nfc_sleep(); + + /* until here the UID field is reversed from the reader IC. + we will read it here again and it will get placed in the right order. */ + card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx); + + return card_read; +} + void nfc_worker_read(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); @@ -304,7 +497,12 @@ void nfc_worker_read(NfcWorker* nfc_worker) { event = NfcWorkerEventReadUidNfcF; break; } else if(nfc_data->type == FuriHalNfcTypeV) { - event = NfcWorkerEventReadUidNfcV; + FURI_LOG_I(TAG, "NfcV detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + if(nfc_worker_read_nfcv(nfc_worker, &tx_rx)) { + FURI_LOG_I(TAG, "nfc_worker_read_nfcv success"); + } + event = NfcWorkerEventReadNfcV; break; } } else { @@ -416,6 +614,32 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { } } +void nfc_worker_emulate_nfcv(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + nfcv_emu_init(nfc_data, nfcv_data); + while(nfc_worker->state == NfcWorkerStateNfcVEmulate) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 50)) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } + } + furi_delay_ms(0); + } + nfcv_emu_deinit(nfcv_data); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcDevData params = { diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index 8e993fc6a..5113205c4 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -18,6 +18,9 @@ typedef enum { NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, NfcWorkerStateAnalyzeReader, + NfcWorkerStateNfcVEmulate, + NfcWorkerStateNfcVUnlock, + NfcWorkerStateNfcVUnlockAndSave, // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, @@ -39,6 +42,7 @@ typedef enum { NfcWorkerEventReadMfClassicDone, NfcWorkerEventReadMfClassicLoadKeyCache, NfcWorkerEventReadMfClassicDictAttackRequired, + NfcWorkerEventReadNfcV, // Nfc worker common events NfcWorkerEventSuccess, @@ -69,6 +73,7 @@ typedef enum { // Mifare Ultralight events NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command + NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); @@ -87,3 +92,5 @@ void nfc_worker_start( void* context); void nfc_worker_stop(NfcWorker* nfc_worker); +void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker); +void nfc_worker_emulate_nfcv(NfcWorker* nfc_worker); diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index 701ecb90c..b678573ec 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include struct NfcWorker { diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c new file mode 100644 index 000000000..6c205779f --- /dev/null +++ b/lib/nfc/protocols/nfcv.c @@ -0,0 +1,885 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfcv.h" +#include "nfc_util.h" +#include "slix.h" + +#define TAG "NfcV" + +ReturnCode nfcv_inventory(uint8_t* uid) { + uint16_t received = 0; + rfalNfcvInventoryRes res; + ReturnCode ret = ERR_NONE; + + for(int tries = 0; tries < 5; tries++) { + /* TODO: needs proper abstraction via fury_hal(_ll)_* */ + ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received); + + if(ret == ERR_NONE) { + break; + } + } + + if(ret == ERR_NONE) { + if(uid != NULL) { + memcpy(uid, res.UID, 8); + } + } + + return ret; +} + +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* nfcv_data) { + UNUSED(reader); + + uint16_t received = 0; + for(size_t block = 0; block < nfcv_data->block_num; block++) { + uint8_t rxBuf[32]; + FURI_LOG_D(TAG, "Reading block %d/%d", block, (nfcv_data->block_num - 1)); + + ReturnCode ret = ERR_NONE; + for(int tries = 0; tries < 5; tries++) { + ret = rfalNfcvPollerReadSingleBlock( + RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, rxBuf, sizeof(rxBuf), &received); + + if(ret == ERR_NONE) { + break; + } + } + if(ret != ERR_NONE) { + FURI_LOG_D(TAG, "failed to read: %d", ret); + return ret; + } + memcpy( + &(nfcv_data->data[block * nfcv_data->block_size]), &rxBuf[1], nfcv_data->block_size); + FURI_LOG_D( + TAG, + " %02X %02X %02X %02X", + nfcv_data->data[block * nfcv_data->block_size + 0], + nfcv_data->data[block * nfcv_data->block_size + 1], + nfcv_data->data[block * nfcv_data->block_size + 2], + nfcv_data->data[block * nfcv_data->block_size + 3]); + } + + return ERR_NONE; +} + +ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + uint8_t rxBuf[32]; + uint16_t received = 0; + ReturnCode ret = ERR_NONE; + + FURI_LOG_D(TAG, "Read SYSTEM INFORMATION..."); + + for(int tries = 0; tries < 5; tries++) { + /* TODO: needs proper abstraction via fury_hal(_ll)_* */ + ret = rfalNfcvPollerGetSystemInformation( + RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, rxBuf, sizeof(rxBuf), &received); + + if(ret == ERR_NONE) { + break; + } + } + + if(ret == ERR_NONE) { + nfc_data->type = FuriHalNfcTypeV; + nfc_data->uid_len = 8; + /* UID is stored reversed in this response */ + for(int pos = 0; pos < nfc_data->uid_len; pos++) { + nfc_data->uid[pos] = rxBuf[2 + (7 - pos)]; + } + nfcv_data->dsfid = rxBuf[10]; + nfcv_data->afi = rxBuf[11]; + nfcv_data->block_num = rxBuf[12] + 1; + nfcv_data->block_size = rxBuf[13] + 1; + nfcv_data->ic_ref = rxBuf[14]; + FURI_LOG_D( + TAG, + " UID: %02X %02X %02X %02X %02X %02X %02X %02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + FURI_LOG_D( + TAG, + " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", + nfcv_data->dsfid, + nfcv_data->afi, + nfcv_data->block_num, + nfcv_data->block_size, + nfcv_data->ic_ref); + return ret; + } + FURI_LOG_D(TAG, "Failed: %d", ret); + + return ret; +} + +bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + furi_assert(reader); + furi_assert(nfc_data); + furi_assert(nfcv_data); + + if(nfcv_read_sysinfo(nfc_data, nfcv_data) != ERR_NONE) { + return false; + } + + if(nfcv_read_blocks(reader, nfcv_data) != ERR_NONE) { + return false; + } + + if(slix_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX detected"); + nfcv_data->sub_type = NfcVTypeSlix; + } else if(slix2_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX2 detected"); + nfcv_data->sub_type = NfcVTypeSlix2; + } else if(slix_s_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX-S detected"); + nfcv_data->sub_type = NfcVTypeSlixS; + } else if(slix_l_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX-L detected"); + nfcv_data->sub_type = NfcVTypeSlixL; + } else { + nfcv_data->sub_type = NfcVTypePlain; + } + + return true; +} + +void nfcv_crc(uint8_t* data, uint32_t length) { + uint32_t reg = 0xFFFF; + + for(size_t i = 0; i < length; i++) { + reg = reg ^ ((uint32_t)data[i]); + for(size_t j = 0; j < 8; j++) { + if(reg & 0x0001) { + reg = (reg >> 1) ^ 0x8408; + } else { + reg = (reg >> 1); + } + } + } + + uint16_t crc = ~(uint16_t)(reg & 0xffff); + + data[length + 0] = crc & 0xFF; + data[length + 1] = crc >> 8; +} + +void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { + if(signals->nfcv_resp_one) { + digital_signal_free(signals->nfcv_resp_one); + signals->nfcv_resp_one = NULL; + } + if(signals->nfcv_resp_zero) { + digital_signal_free(signals->nfcv_resp_zero); + signals->nfcv_resp_zero = NULL; + } + if(signals->nfcv_resp_sof) { + digital_signal_free(signals->nfcv_resp_sof); + signals->nfcv_resp_sof = NULL; + } + if(signals->nfcv_resp_eof) { + digital_signal_free(signals->nfcv_resp_eof); + signals->nfcv_resp_eof = NULL; + } +} + +void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { + if(!signals->nfcv_resp_one) { + /* logical one: unmodulated then 8 pulses */ + signals->nfcv_resp_one = digital_signal_alloc(40); + for(size_t i = 0; i < slowdown; i++) { + digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); + } + for(size_t i = 0; i < slowdown * 8; i++) { + digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); + } + } + if(!signals->nfcv_resp_zero) { + /* logical zero: 8 pulses then unmodulated */ + signals->nfcv_resp_zero = digital_signal_alloc(40); + for(size_t i = 0; i < slowdown * 8; i++) { + digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); + } + for(size_t i = 0; i < slowdown; i++) { + digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); + } + } + if(!signals->nfcv_resp_sof) { + /* SOF: unmodulated, 24 pulses, logic 1 */ + signals->nfcv_resp_sof = digital_signal_alloc(160); + for(size_t i = 0; i < slowdown * 3; i++) { + digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); + } + for(size_t i = 0; i < slowdown * 24; i++) { + digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); + } + digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); + } + if(!signals->nfcv_resp_eof) { + /* EOF: logic 0, 24 pulses, unmodulated */ + signals->nfcv_resp_eof = digital_signal_alloc(160); + digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); + for(size_t i = 0; i < slowdown * 24; i++) { + digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); + } + for(size_t i = 0; i < slowdown * 3; i++) { + digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + } + /* add extra silence */ + digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + } +} + +void nfcv_emu_alloc(NfcVData* nfcv_data) { + if(!nfcv_data->emu_air.nfcv_signal) { + /* assuming max frame length is 255 bytes */ + nfcv_data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); + } + if(!nfcv_data->emu_air.nfcv_resp_unmod) { + /* unmodulated 256/fc or 1024/fc signal as building block */ + nfcv_data->emu_air.nfcv_resp_unmod = digital_signal_alloc(4); + nfcv_data->emu_air.nfcv_resp_unmod->start_level = false; + nfcv_data->emu_air.nfcv_resp_unmod->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_unmod->edge_cnt = 1; + } + if(!nfcv_data->emu_air.nfcv_resp_pulse) { + /* modulated fc/32 or fc/8 pulse as building block */ + nfcv_data->emu_air.nfcv_resp_pulse = digital_signal_alloc(4); + nfcv_data->emu_air.nfcv_resp_pulse->start_level = true; + nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[1] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_pulse->edge_cnt = 2; + } + + nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); + nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); + + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_SOF, + nfcv_data->emu_air.signals_high.nfcv_resp_sof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_BIT0, + nfcv_data->emu_air.signals_high.nfcv_resp_zero); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_BIT1, + nfcv_data->emu_air.signals_high.nfcv_resp_one); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_EOF, + nfcv_data->emu_air.signals_high.nfcv_resp_eof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_SOF, + nfcv_data->emu_air.signals_low.nfcv_resp_sof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_BIT0, + nfcv_data->emu_air.signals_low.nfcv_resp_zero); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_BIT1, + nfcv_data->emu_air.signals_low.nfcv_resp_one); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_EOF, + nfcv_data->emu_air.signals_low.nfcv_resp_eof); +} + +void nfcv_emu_free(NfcVData* nfcv_data) { + if(nfcv_data->emu_air.nfcv_resp_unmod) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); + nfcv_data->emu_air.nfcv_resp_unmod = NULL; + } + if(nfcv_data->emu_air.nfcv_resp_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); + nfcv_data->emu_air.nfcv_resp_pulse = NULL; + } + if(nfcv_data->emu_air.nfcv_signal) { + digital_sequence_free(nfcv_data->emu_air.nfcv_signal); + nfcv_data->emu_air.nfcv_signal = NULL; + } + if(nfcv_data->emu_air.reader_signal) { + pulse_reader_free(nfcv_data->emu_air.reader_signal); + nfcv_data->emu_air.reader_signal = NULL; + } + + nfcv_emu_free_signals(&nfcv_data->emu_air.signals_high); + nfcv_emu_free_signals(&nfcv_data->emu_air.signals_low); +} + +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags, + uint32_t send_time) { + /* picked default value (0) to match the most common format */ + if(!flags) { + flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | + NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate; + } + + if(flags & NfcVSendFlagsCrc) { + nfcv_crc(data, length); + length += 2; + } + + /* depending on the request flags, send with high or low rate */ + uint32_t bit0 = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_BIT0 : NFCV_SIG_LOW_BIT0; + uint32_t bit1 = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_BIT1 : NFCV_SIG_LOW_BIT1; + uint32_t sof = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_SOF : NFCV_SIG_LOW_SOF; + uint32_t eof = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_EOF : NFCV_SIG_LOW_EOF; + + digital_sequence_clear(nfcv->emu_air.nfcv_signal); + + if(flags & NfcVSendFlagsSof) { + digital_sequence_add(nfcv->emu_air.nfcv_signal, sof); + } + + for(int bit_total = 0; bit_total < length * 8; bit_total++) { + uint32_t byte_pos = bit_total / 8; + uint32_t bit_pos = bit_total % 8; + uint8_t bit_val = 0x01 << bit_pos; + + digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? bit1 : bit0); + } + + if(flags & NfcVSendFlagsEof) { + digital_sequence_add(nfcv->emu_air.nfcv_signal, eof); + } + + FURI_CRITICAL_ENTER(); + digital_sequence_set_sendtime(nfcv->emu_air.nfcv_signal, send_time); + digital_sequence_send(nfcv->emu_air.nfcv_signal); + FURI_CRITICAL_EXIT(); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(data, length * 8, false, tx_rx->sniff_context); + } +} + +static void nfcv_revuidcpy(uint8_t* dst, uint8_t* src) { + for(int pos = 0; pos < 8; pos++) { + dst[pos] = src[7 - pos]; + } +} + +static int nfcv_revuidcmp(uint8_t* dst, uint8_t* src) { + for(int pos = 0; pos < 8; pos++) { + if(dst[pos] != src[7 - pos]) { + return 1; + } + } + return 0; +} + +void nfcv_emu_handle_packet( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + + if(nfcv_data->frame_length < 2) { + return; + } + + /* parse the frame data for the upcoming part 3 handling */ + ctx->flags = nfcv_data->frame[0]; + ctx->command = nfcv_data->frame[1]; + ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && + (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); + ctx->advanced = (ctx->command >= 0xA0); + ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); + ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); + ctx->response_flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof; + ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4130); + + if(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) { + ctx->response_flags |= NfcVSendFlagsHighRate; + } + if(ctx->flags & RFAL_NFCV_REQ_FLAG_SUB_CARRIER) { + ctx->response_flags |= NfcVSendFlagsTwoSubcarrier; + } + + /* standard behavior is implemented */ + if(ctx->addressed) { + uint8_t* address = &nfcv_data->frame[ctx->address_offset]; + if(nfcv_revuidcmp(address, nfc_data->uid)) { + FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); + FURI_LOG_D( + TAG, + " dest: %02X%02X%02X%02X%02X%02X%02X%02X", + address[7], + address[6], + address[5], + address[4], + address[3], + address[2], + address[1], + address[0]); + FURI_LOG_D( + TAG, + " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + return; + } + } + + /* then give control to the card subtype specific protocol filter */ + if(ctx->emu_protocol_filter != NULL) { + if(ctx->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) { + if(strlen(nfcv_data->last_command) > 0) { + FURI_LOG_D( + TAG, "Received command %s (handled by filter)", nfcv_data->last_command); + } + return; + } + } + + switch(ctx->command) { + case ISO15693_INVENTORY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = nfcv_data->dsfid; + nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid); + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + break; + } + + case ISO15693_STAYQUIET: { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET"); + break; + } + + case ISO15693_LOCKBLOCK: { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK"); + break; + } + + case ISO15693_SELECT: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); + break; + } + + case ISO15693_RESET_TO_READY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "RESET_TO_READY"); + break; + } + + case ISO15693_READ_MULTI_BLOCK: + case ISO15693_READBLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + + if(ctx->command == ISO15693_READ_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + } + + if(block + blocks > nfcv_data->block_num) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } else { + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy( + &ctx->response_buffer[1], + &nfcv_data->data[nfcv_data->block_size * block], + nfcv_data->block_size * blocks); + nfcv_emu_send( + tx_rx, + nfcv_data, + ctx->response_buffer, + 1 + nfcv_data->block_size * blocks, + ctx->response_flags, + ctx->send_time); + } + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); + break; + } + + case ISO15693_WRITE_MULTI_BLOCK: + case ISO15693_WRITEBLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + uint8_t data_pos = 1; + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + data_pos++; + } + + uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos]; + uint32_t data_len = nfcv_data->block_size * blocks; + + if(block + blocks > nfcv_data->block_num || + ctx->payload_offset + data_len + 2 > nfcv_data->frame_length) { + ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; + } else { + ctx->response_buffer[0] = ISO15693_NOERROR; + memcpy( + &nfcv_data->data[nfcv_data->block_size * block], + &nfcv_data->frame[ctx->payload_offset + data_pos], + data_len); + } + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE MULTI BLOCK %d, %d blocks", + block, + blocks); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE BLOCK %d <- %02X %02X %02X %02X", + block, + data[0], + data[1], + data[2], + data[3]); + } + break; + } + + case ISO15693_GET_SYSTEM_INFO: { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = 0x0F; + nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid); + ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */ + ctx->response_buffer[11] = nfcv_data->afi; /* AFI */ + ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */ + ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */ + ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */ + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO"); + break; + } + + default: + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "unsupported: %02X", + ctx->command); + break; + } + + if(strlen(nfcv_data->last_command) > 0) { + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); + } +} + +void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + nfcv_emu_alloc(nfcv_data); + rfal_platform_spi_acquire(); + /* configure for transparent and passive mode */ + st25r3916ExecuteCommand(ST25R3916_CMD_STOP); + /* set enable, rx_enable and field detector enable */ + st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3); + /* target mode: ISO14443 passive mode */ + st25r3916WriteRegister(ST25R3916_REG_MODE, 0x88); + /* let us modulate the field using MOSI, read modulation using MISO */ + st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); + + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + + /* if not set already, initialize the default protocol handler */ + if(!nfcv_data->emu_protocol_ctx) { + nfcv_data->emu_protocol_ctx = malloc(sizeof(NfcVEmuProtocolCtx)); + nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; + } + + FURI_LOG_D(TAG, "Starting NfcV emulation"); + FURI_LOG_D( + TAG, + " UID: %02X %02X %02X %02X %02X %02X %02X %02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + + switch(nfcv_data->sub_type) { + case NfcVTypeSlixL: + FURI_LOG_D(TAG, " Card type: SLIX-L"); + slix_l_prepare(nfcv_data); + break; + case NfcVTypeSlixS: + FURI_LOG_D(TAG, " Card type: SLIX-S"); + slix_s_prepare(nfcv_data); + break; + case NfcVTypeSlix2: + FURI_LOG_D(TAG, " Card type: SLIX2"); + slix2_prepare(nfcv_data); + break; + case NfcVTypeSlix: + FURI_LOG_D(TAG, " Card type: SLIX"); + slix_prepare(nfcv_data); + break; + case NfcVTypePlain: + FURI_LOG_D(TAG, " Card type: Plain"); + break; + } + + /* allocate a 512 edge buffer, more than enough */ + nfcv_data->emu_air.reader_signal = pulse_reader_alloc(&gpio_nfc_irq_rfid_pull, 512); + /* timebase shall be 1 ns */ + pulse_reader_set_timebase(nfcv_data->emu_air.reader_signal, PulseReaderUnitNanosecond); + /* and configure to already calculate the number of bits */ + pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, PULSE_DURATION_NS); + /* this IO is fed into the µC via a diode, so we need a pulldown */ + pulse_reader_set_pull(nfcv_data->emu_air.reader_signal, GpioPullDown); + + /* start sampling */ + pulse_reader_start(nfcv_data->emu_air.reader_signal); +} + +void nfcv_emu_deinit(NfcVData* nfcv_data) { + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); + rfal_platform_spi_release(); + nfcv_emu_free(nfcv_data); + + if(nfcv_data->emu_protocol_ctx) { + free(nfcv_data->emu_protocol_ctx); + nfcv_data->emu_protocol_ctx = NULL; + } + + /* set registers back to how we found them */ + st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0x00); + st25r3916WriteRegister(ST25R3916_REG_MODE, 0x08); +} + +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms) { + bool ret = false; + uint32_t frame_state = NFCV_FRAME_STATE_SOF1; + uint32_t periods_previous = 0; + uint8_t frame_payload[128]; + uint32_t frame_pos = 0; + uint32_t byte_value = 0; + uint32_t bits_received = 0; + char reset_reason[128]; + bool wait_for_pulse = false; + + while(true) { + uint32_t periods = + pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); + uint32_t timestamp = DWT->CYCCNT; + + if(periods == PULSE_READER_NO_EDGE) { + break; + } + if(periods == PULSE_READER_LOST_EDGE) { + break; + } + + if(wait_for_pulse) { + wait_for_pulse = false; + if(periods != 1) { + snprintf( + reset_reason, + sizeof(reset_reason), + "SOF: Expected a single low pulse in state %lu, but got %lu", + frame_state, + periods); + frame_state = NFCV_FRAME_STATE_RESET; + } + continue; + } + + switch(frame_state) { + case NFCV_FRAME_STATE_SOF1: + if(periods == 1) { + frame_state = NFCV_FRAME_STATE_SOF2; + } else { + frame_state = NFCV_FRAME_STATE_SOF1; + break; + } + break; + + case NFCV_FRAME_STATE_SOF2: + /* waiting for the second low period, telling us about coding */ + if(periods == 6) { + frame_state = NFCV_FRAME_STATE_CODING_256; + periods_previous = 0; + wait_for_pulse = true; + } else if(periods == 4) { + frame_state = NFCV_FRAME_STATE_CODING_4; + periods_previous = 2; + wait_for_pulse = true; + } else { + snprintf( + reset_reason, + sizeof(reset_reason), + "SOF: Expected 4/6 periods, got %lu", + periods); + frame_state = NFCV_FRAME_STATE_SOF1; + } + break; + + case NFCV_FRAME_STATE_CODING_256: + if(periods_previous > periods) { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo256: Missing %lu periods from previous symbol, got %lu", + periods_previous, + periods); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + + if(periods > 512) { + snprintf( + reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } + + periods_previous = 512 - (periods + 1); + byte_value = (periods - 1) / 2; + frame_payload[frame_pos++] = (uint8_t)byte_value; + + wait_for_pulse = true; + + break; + + case NFCV_FRAME_STATE_CODING_4: + if(periods_previous > periods) { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo4: Missing %lu periods from previous symbol, got %lu at pos %lu", + periods_previous, + periods, + frame_pos); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + periods_previous = 0; + + byte_value >>= 2; + bits_received += 2; + + if(periods == 1) { + byte_value |= 0x00 << 6; + periods_previous = 6; + } else if(periods == 3) { + byte_value |= 0x01 << 6; + periods_previous = 4; + } else if(periods == 5) { + byte_value |= 0x02 << 6; + periods_previous = 2; + } else if(periods == 7) { + byte_value |= 0x03 << 6; + periods_previous = 0; + } else if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } else { + snprintf( + reset_reason, + sizeof(reset_reason), + "1oo4: Expected 1/3/5/7 low pulses, but got %lu at pos %lu", + periods, + frame_pos); + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + if(bits_received >= 8) { + frame_payload[frame_pos++] = (uint8_t)byte_value; + bits_received = 0; + } + wait_for_pulse = true; + break; + } + + /* post-state-machine cleanup and reset */ + if(frame_state == NFCV_FRAME_STATE_RESET) { + frame_state = NFCV_FRAME_STATE_SOF1; + + FURI_LOG_D(TAG, "Resetting state machine, reason: '%s'", reset_reason); + } else if(frame_state == NFCV_FRAME_STATE_EOF) { + nfcv_data->frame = frame_payload; + nfcv_data->frame_length = frame_pos; + nfcv_data->eof_timestamp = timestamp; + break; + } + } + + if(frame_state == NFCV_FRAME_STATE_EOF) { + /* we know that this code uses TIM2, so stop pulse reader */ + pulse_reader_stop(nfcv_data->emu_air.reader_signal); + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context); + } + nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + pulse_reader_start(nfcv_data->emu_air.reader_signal); + ret = true; + } + + return ret; +} diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h new file mode 100644 index 000000000..9d7a56326 --- /dev/null +++ b/lib/nfc/protocols/nfcv.h @@ -0,0 +1,213 @@ +#pragma once + +#include +#include + +#include +#include +#include "nfc_util.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFCV_FC (13560000.0f) /* MHz */ +#define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */ +#define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */ + +#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC) /* ns */ + +#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) +#define DIGITAL_SIGNAL_UNIT_US (100000.0f) + +#define NFCV_TOTAL_BLOCKS_MAX 256 +#define NFCV_BLOCK_SIZE 4 +#define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE * NFCV_TOTAL_BLOCKS_MAX) + +/* helpers to calculate the send time based on DWT->CYCCNT */ +#define NFCV_FDT_USEC(usec) (usec * 64) +#define NFCV_FDT_FC(ticks) (ticks * 6400 / 1356) + +#define NFCV_FRAME_STATE_SOF1 0 +#define NFCV_FRAME_STATE_SOF2 1 +#define NFCV_FRAME_STATE_CODING_4 2 +#define NFCV_FRAME_STATE_CODING_256 3 +#define NFCV_FRAME_STATE_EOF 4 +#define NFCV_FRAME_STATE_RESET 5 + +/* sequences for every section of a frame */ +#define NFCV_SIG_SOF 0 +#define NFCV_SIG_BIT0 1 +#define NFCV_SIG_BIT1 2 +#define NFCV_SIG_EOF 3 +#define NFCV_SIG_LOW_SOF 4 +#define NFCV_SIG_LOW_BIT0 5 +#define NFCV_SIG_LOW_BIT1 6 +#define NFCV_SIG_LOW_EOF 7 + +/* ISO15693 command codes */ +#define ISO15693_INVENTORY 0x01 +#define ISO15693_STAYQUIET 0x02 +#define ISO15693_READBLOCK 0x20 +#define ISO15693_WRITEBLOCK 0x21 +#define ISO15693_LOCKBLOCK 0x22 +#define ISO15693_READ_MULTI_BLOCK 0x23 +#define ISO15693_WRITE_MULTI_BLOCK 0x24 +#define ISO15693_SELECT 0x25 +#define ISO15693_RESET_TO_READY 0x26 +#define ISO15693_WRITE_AFI 0x27 +#define ISO15693_LOCK_AFI 0x28 +#define ISO15693_WRITE_DSFID 0x29 +#define ISO15693_LOCK_DSFID 0x2A +#define ISO15693_GET_SYSTEM_INFO 0x2B +#define ISO15693_READ_MULTI_SECSTATUS 0x2C + +/* ISO15693 RESPONSE ERROR CODES */ +#define ISO15693_NOERROR 0x00 +#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported +#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) +#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported +#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error +#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10 +#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again +#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed +#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful +#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful + +typedef enum { + NfcVAuthMethodManual, + NfcVAuthMethodTonieBox, +} NfcVAuthMethod; + +typedef enum { + NfcVTypePlain = 0, + NfcVTypeSlix = 1, + NfcVTypeSlixS = 2, + NfcVTypeSlixL = 3, + NfcVTypeSlix2 = 4, +} NfcVSubtype; + +typedef enum { + NfcVSendFlagsNormal = 0, + NfcVSendFlagsSof = 1 << 0, + NfcVSendFlagsCrc = 1 << 1, + NfcVSendFlagsEof = 1 << 2, + NfcVSendFlagsOneSubcarrier = 0, + NfcVSendFlagsTwoSubcarrier = 1 << 3, + NfcVSendFlagsLowRate = 0, + NfcVSendFlagsHighRate = 1 << 4 +} NfcVSendFlags; + +typedef struct { + uint8_t key_read[4]; + uint8_t key_write[4]; + uint8_t key_privacy[4]; + uint8_t key_destroy[4]; + uint8_t key_eas[4]; + uint8_t rand[2]; + bool privacy; +} NfcVSlixData; + +typedef union { + NfcVSlixData slix; +} NfcVSubtypeData; + +typedef struct { + DigitalSignal* nfcv_resp_sof; + DigitalSignal* nfcv_resp_one; + DigitalSignal* nfcv_resp_zero; + DigitalSignal* nfcv_resp_eof; +} NfcVEmuAirSignals; + +typedef struct { + PulseReader* reader_signal; + DigitalSignal* nfcv_resp_pulse; /* pulse length, fc/32 */ + DigitalSignal* nfcv_resp_unmod; /* unmodulated length 256/fc */ + NfcVEmuAirSignals signals_high; + NfcVEmuAirSignals signals_low; + DigitalSequence* nfcv_signal; +} NfcVEmuAir; + +typedef void (*NfcVEmuProtocolHandler)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data); +typedef bool (*NfcVEmuProtocolFilter)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data); + +typedef struct { + uint8_t flags; /* ISO15693-3 flags of the header as specified */ + uint8_t command; /* ISO15693-3 command at offset 1 as specified */ + bool addressed; /* ISO15693-3 flags: addressed frame */ + bool advanced; /* ISO15693-3 command: advanced command */ + uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ + uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ + + uint8_t response_buffer[128]; /* pre-allocated response buffer */ + NfcVSendFlags response_flags; /* flags to use when sending response */ + uint32_t send_time; /* timestamp when to send the response */ + + NfcVEmuProtocolFilter emu_protocol_filter; +} NfcVEmuProtocolCtx; + +typedef struct { + /* common ISO15693 fields, being specified in ISO15693-3 */ + uint8_t dsfid; + uint8_t afi; + uint8_t ic_ref; + uint16_t block_num; + uint8_t block_size; + uint8_t data[NFCV_MAX_DUMP_SIZE]; + + /* specfic variant infos */ + NfcVSubtype sub_type; + NfcVSubtypeData sub_data; + NfcVAuthMethod auth_method; + + /* precalced air level data */ + NfcVEmuAir emu_air; + + uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */ + uint8_t frame_length; /* ISO15693-2 length of incoming data */ + uint32_t eof_timestamp; /* ISO15693-2 EOF timestamp, read from DWT->CYCCNT */ + + /* handler for the protocol layer as specified in ISO15693-3 */ + NfcVEmuProtocolHandler emu_protocol_handler; + void* emu_protocol_ctx; + + /* runtime data */ + char last_command[128]; + char error[32]; +} NfcVData; + +typedef struct { + uint16_t blocks_to_read; + int16_t blocks_read; +} NfcVReader; + +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data); +ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data); +ReturnCode nfcv_inventory(uint8_t* uid); +bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data); + +void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data); +void nfcv_emu_deinit(NfcVData* nfcv_data); +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms); +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags, + uint32_t send_time); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c new file mode 100644 index 000000000..e61c70919 --- /dev/null +++ b/lib/nfc/protocols/slix.c @@ -0,0 +1,407 @@ + +#include +#include "nfcv.h" +#include "slix.h" +#include "nfc_util.h" +#include +#include "furi_hal_nfc.h" +#include + +#define TAG "SLIX" + +static uint32_t slix_read_be(uint8_t* data, uint32_t length) { + uint32_t value = 0; + + for(uint32_t pos = 0; pos < length; pos++) { + value <<= 8; + value |= data[pos]; + } + + return value; +} + +uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) { + return (nfc_data->uid[3] >> 3) & 3; +} + +bool slix_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) && + slix_get_ti(nfc_data) == 2) { + return true; + } + return false; +} + +bool slix2_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) && + slix_get_ti(nfc_data) == 1) { + return true; + } + return false; +} + +bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x02)) { + return true; + } + return false; +} + +bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x03)) { + return true; + } + return false; +} + +ReturnCode slix_get_random(NfcVData* data) { + uint16_t received = 0; + uint8_t rxBuf[32]; + + ReturnCode ret = rfalNfcvPollerTransceiveReq( + ISO15693_CMD_NXP_GET_RANDOM_NUMBER, + RFAL_NFCV_REQ_FLAG_DEFAULT, + ISO15693_MANUFACTURER_NXP, + NULL, + NULL, + 0, + rxBuf, + sizeof(rxBuf), + &received); + + if(ret == ERR_NONE) { + if(received != 3) { + return ERR_PROTO; + } + if(data != NULL) { + data->sub_data.slix.rand[0] = rxBuf[2]; + data->sub_data.slix.rand[1] = rxBuf[1]; + } + } + + return ret; +} + +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) { + furi_assert(rand); + + uint16_t received = 0; + uint8_t rxBuf[32]; + uint8_t cmd_set_pass[] = { + password_id, + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0], + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0]}; + uint8_t* password = NULL; + + switch(password_id) { + case SLIX_PASS_READ: + password = data->sub_data.slix.key_read; + break; + case SLIX_PASS_WRITE: + password = data->sub_data.slix.key_write; + break; + case SLIX_PASS_PRIVACY: + password = data->sub_data.slix.key_privacy; + break; + case SLIX_PASS_DESTROY: + password = data->sub_data.slix.key_destroy; + break; + case SLIX_PASS_EASAFI: + password = data->sub_data.slix.key_eas; + break; + default: + break; + } + + if(!password) { + return ERR_NOTSUPP; + } + + for(int pos = 0; pos < 4; pos++) { + cmd_set_pass[1 + pos] ^= password[3 - pos]; + } + + ReturnCode ret = rfalNfcvPollerTransceiveReq( + ISO15693_CMD_NXP_SET_PASSWORD, + RFAL_NFCV_REQ_FLAG_DATA_RATE, + ISO15693_MANUFACTURER_NXP, + NULL, + cmd_set_pass, + sizeof(cmd_set_pass), + rxBuf, + sizeof(rxBuf), + &received); + + return ret; +} + +bool slix_generic_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in, + uint32_t password_supported) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + NfcVSlixData* slix = &nfcv_data->sub_data.slix; + + if(slix->privacy && ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER && + ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "command 0x%02X ignored, privacy mode", + ctx->command); + FURI_LOG_D(TAG, "%s", nfcv_data->last_command); + return true; + } + + bool handled = false; + + switch(ctx->command) { + case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: { + slix->rand[0] = furi_hal_random_get(); + slix->rand[1] = furi_hal_random_get(); + + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = slix->rand[1]; + ctx->response_buffer[2] = slix->rand[0]; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "GET_RANDOM_NUMBER -> 0x%02X%02X", + slix->rand[0], + slix->rand[1]); + + handled = true; + break; + } + + case ISO15693_CMD_NXP_SET_PASSWORD: { + uint8_t password_id = nfcv_data->frame[ctx->payload_offset]; + + if(!(password_id & password_supported)) { + break; + } + + uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1]; + uint8_t* rand = slix->rand; + uint8_t* password = NULL; + uint8_t password_rcv[4]; + + switch(password_id) { + case SLIX_PASS_READ: + password = slix->key_read; + break; + case SLIX_PASS_WRITE: + password = slix->key_write; + break; + case SLIX_PASS_PRIVACY: + password = slix->key_privacy; + break; + case SLIX_PASS_DESTROY: + password = slix->key_destroy; + break; + case SLIX_PASS_EASAFI: + password = slix->key_eas; + break; + default: + break; + } + + for(int pos = 0; pos < 4; pos++) { + password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; + } + uint32_t pass_expect = slix_read_be(password, 4); + uint32_t pass_received = slix_read_be(password_rcv, 4); + + /* if the password is all-zeroes, just accept any password*/ + if(!pass_expect || pass_expect == pass_received) { + switch(password_id) { + case SLIX_PASS_READ: + break; + case SLIX_PASS_WRITE: + break; + case SLIX_PASS_PRIVACY: + slix->privacy = false; + break; + case SLIX_PASS_DESTROY: + FURI_LOG_D(TAG, "Pooof! Got destroyed"); + break; + case SLIX_PASS_EASAFI: + break; + default: + break; + } + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX OK", + password_id, + pass_received); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", + password_id, + pass_received, + pass_expect); + } + handled = true; + break; + } + + case ISO15693_CMD_NXP_ENABLE_PRIVACY: { + ctx->response_buffer[0] = ISO15693_NOERROR; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "ISO15693_CMD_NXP_ENABLE_PRIVACY"); + + slix->privacy = true; + handled = true; + break; + } + } + + return handled; +} + +bool slix_l_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter( + tx_rx, + nfc_data, + nfcv_data_in, + SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_l_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_l_protocol_filter; +} + +bool slix_s_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix_s_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_s_protocol_filter; +} + +bool slix_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_protocol_filter; +} + +bool slix2_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix2_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix2_protocol_filter; +} diff --git a/lib/nfc/protocols/slix.h b/lib/nfc/protocols/slix.h new file mode 100644 index 000000000..719fe6f43 --- /dev/null +++ b/lib/nfc/protocols/slix.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include "nfc_util.h" +#include + +#define ISO15693_MANUFACTURER_NXP 0x04 + +/* ISO15693-3 CUSTOM NXP COMMANDS */ +#define ISO15693_CMD_NXP_SET_EAS 0xA2 +#define ISO15693_CMD_NXP_RESET_EAS 0xA3 +#define ISO15693_CMD_NXP_LOCK_EAS 0xA4 +#define ISO15693_CMD_NXP_EAS_ALARM 0xA5 +#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 +#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0 +#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 +#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2 +#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3 +#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4 +#define ISO15693_CMD_NXP_DESTROY 0xB9 +#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA + +/* available passwords */ +#define SLIX_PASS_READ 0x01 +#define SLIX_PASS_WRITE 0x02 +#define SLIX_PASS_PRIVACY 0x04 +#define SLIX_PASS_DESTROY 0x08 +#define SLIX_PASS_EASAFI 0x10 + +#define SLIX_PASS_ALL \ + (SLIX_PASS_READ | SLIX_PASS_WRITE | SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI) + +bool slix_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix2_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data); + +ReturnCode slix_get_random(NfcVData* data); +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id); + +void slix_prepare(NfcVData* nfcv_data); +void slix_s_prepare(NfcVData* nfcv_data); +void slix_l_prepare(NfcVData* nfcv_data); +void slix2_prepare(NfcVData* nfcv_data); From 423c551cf143460590940005e9c0c894858e59f3 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 20:53:21 +0100 Subject: [PATCH 042/216] SLIX: fixed crash situation when an invalid password was requested --- lib/nfc/protocols/slix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index e61c70919..6c6deacdd 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -217,6 +217,10 @@ bool slix_generic_protocol_filter( break; } + if(!password) { + break; + } + for(int pos = 0; pos < 4; pos++) { password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; } From 5d14755302e9d24c1a7d781d31945f95478804c8 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 21:50:05 +0100 Subject: [PATCH 043/216] ISO15693: show emulate menu when opening file --- applications/main/nfc/scenes/nfc_scene_saved_menu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index b7fc66995..0f49c4e4b 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -43,6 +43,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { } } else if( nfc->dev->format == NfcDeviceSaveFormatMifareUl || + nfc->dev->format == NfcDeviceSaveFormatNfcV || nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); From 2c313edcdb3621047e4fa0aed929d031e662875e Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 22:02:02 +0100 Subject: [PATCH 044/216] rename NfcV emulate scene to match other NfcV names --- applications/main/nfc/nfc.c | 2 +- .../main/nfc/scenes/nfc_scene_config.h | 2 +- ...mulate_nfcv.c => nfc_scene_nfcv_emulate.c} | 42 +++++++++---------- .../main/nfc/scenes/nfc_scene_nfcv_menu.c | 4 +- .../main/nfc/scenes/nfc_scene_nfcv_unlock.c | 13 +++--- .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 +- 6 files changed, 32 insertions(+), 33 deletions(-) rename applications/main/nfc/scenes/{nfc_scene_emulate_nfcv.c => nfc_scene_nfcv_emulate.c} (77%) diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index a70a52f57..f68b7f2f2 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -291,7 +291,7 @@ int32_t nfc_app(void* p) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); DOLPHIN_DEED(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); DOLPHIN_DEED(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 8f1011e75..b4d5a6e1d 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -18,7 +18,7 @@ ADD_SCENE(nfc, nfcv_menu, NfcVMenu) ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) -ADD_SCENE(nfc, emulate_nfcv, EmulateNfcV) +ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c similarity index 77% rename from applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c rename to applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c index e6fc60d86..53da36679 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c @@ -3,11 +3,11 @@ #define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (100) enum { - NfcSceneEmulateNfcVStateWidget, - NfcSceneEmulateNfcVStateTextBox, + NfcSceneNfcVEmulateStateWidget, + NfcSceneNfcVEmulateStateTextBox, }; -bool nfc_emulate_nfcv_worker_callback(NfcWorkerEvent event, void* context) { +bool nfc_scene_nfcv_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); Nfc* nfc = context; @@ -15,7 +15,7 @@ bool nfc_emulate_nfcv_worker_callback(NfcWorkerEvent event, void* context) { return true; } -void nfc_scene_emulate_nfcv_widget_callback(GuiButtonType result, InputType type, void* context) { +void nfc_scene_nfcv_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); Nfc* nfc = context; if(type == InputTypeShort) { @@ -23,14 +23,14 @@ void nfc_scene_emulate_nfcv_widget_callback(GuiButtonType result, InputType type } } -void nfc_emulate_nfcv_textbox_callback(void* context) { +void nfc_scene_nfcv_emulate_textbox_callback(void* context) { furi_assert(context); Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } // Add widget with device name or inform that data received -static void nfc_scene_emulate_nfcv_widget_config(Nfc* nfc, bool data_received) { +static void nfc_scene_nfcv_emulate_widget_config(Nfc* nfc, bool data_received) { FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; widget_reset(widget); @@ -53,15 +53,15 @@ static void nfc_scene_emulate_nfcv_widget_config(Nfc* nfc, bool data_received) { furi_string_free(info_str); if(data_received) { widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_nfcv_widget_callback, nfc); + widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_emulate_widget_callback, nfc); } } -void nfc_scene_emulate_nfcv_on_enter(void* context) { +void nfc_scene_nfcv_emulate_on_enter(void* context) { Nfc* nfc = context; // Setup Widget - nfc_scene_emulate_nfcv_widget_config(nfc, false); + nfc_scene_nfcv_emulate_widget_config(nfc, false); // Setup TextBox TextBox* text_box = nfc->text_box; text_box_set_font(text_box, TextBoxFontHex); @@ -70,7 +70,7 @@ void nfc_scene_emulate_nfcv_on_enter(void* context) { // Set Widget state and view scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); // Start worker memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); @@ -78,23 +78,23 @@ void nfc_scene_emulate_nfcv_on_enter(void* context) { nfc->worker, NfcWorkerStateNfcVEmulate, &nfc->dev->dev_data, - nfc_emulate_nfcv_worker_callback, + nfc_scene_nfcv_emulate_worker_callback, nfc); nfc_blink_emulate_start(nfc); } -bool nfc_scene_emulate_nfcv_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateNfcV); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVEmulate); bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { // Add data button to widget if data is received for the first time if(!furi_string_size(nfc->text_box_store)) { - nfc_scene_emulate_nfcv_widget_config(nfc, true); + nfc_scene_nfcv_emulate_widget_config(nfc, true); } if(strlen(nfcv_data->last_command) > 0) { /* use the last n bytes from the log so there's enough space for the new log entry */ @@ -111,22 +111,22 @@ bool nfc_scene_emulate_nfcv_on_event(void* context, SceneManagerEvent event) { strcpy(nfcv_data->last_command, ""); } consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateNfcVStateWidget) { + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVEmulateStateWidget) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateTextBox); + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateTextBox); consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateNfcVStateTextBox) { + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVEmulateStateTextBox) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneEmulateNfcVStateTextBox) { + if(state == NfcSceneNfcVEmulateStateTextBox) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); consumed = true; } } @@ -134,7 +134,7 @@ bool nfc_scene_emulate_nfcv_on_event(void* context, SceneManagerEvent event) { return consumed; } -void nfc_scene_emulate_nfcv_on_exit(void* context) { +void nfc_scene_nfcv_emulate_on_exit(void* context) { Nfc* nfc = context; // Stop worker diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c index b30495a05..44d677513 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c @@ -16,9 +16,9 @@ void nfc_scene_nfcv_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; - submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc); submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu)); @@ -38,7 +38,7 @@ bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { DOLPHIN_DEED(DolphinDeedNfcAddEmulate); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c index b52cc0caa..26de304de 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c @@ -42,10 +42,10 @@ void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) { popup_reset(popup); if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) { - nfc_text_store_set( - nfc, - "%s/SLIX_%02X%02X%02X%02X%02X%02X%02X%02X%s", - NFC_APP_FOLDER, + snprintf( + nfc->dev->dev_name, + sizeof(nfc->dev->dev_name), + "SLIX_%02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], @@ -53,12 +53,11 @@ void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) { nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], - nfc_data->uid[7], - NFC_APP_EXTENSION); + nfc_data->uid[7]); nfc->dev->format = NfcDeviceSaveFormatNfcV; - if(nfc_device_save(nfc->dev, nfc->text_store)) { + if(nfc_save_file(nfc)) { popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop); } else { popup_set_header( diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 0f49c4e4b..2d429a59a 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -118,7 +118,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } From d52432970bb0d1a895eefb7c158dba4b3a2c4f89 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 22:02:34 +0100 Subject: [PATCH 045/216] optimize allocation size for signals --- lib/nfc/protocols/nfcv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 6c205779f..0f9a0b58a 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -202,7 +202,7 @@ void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { if(!signals->nfcv_resp_one) { /* logical one: unmodulated then 8 pulses */ - signals->nfcv_resp_one = digital_signal_alloc(40); + signals->nfcv_resp_one = digital_signal_alloc(slowdown * 9); for(size_t i = 0; i < slowdown; i++) { digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); } @@ -212,7 +212,7 @@ void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ } if(!signals->nfcv_resp_zero) { /* logical zero: 8 pulses then unmodulated */ - signals->nfcv_resp_zero = digital_signal_alloc(40); + signals->nfcv_resp_zero = digital_signal_alloc(slowdown * 9); for(size_t i = 0; i < slowdown * 8; i++) { digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); } @@ -222,7 +222,8 @@ void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ } if(!signals->nfcv_resp_sof) { /* SOF: unmodulated, 24 pulses, logic 1 */ - signals->nfcv_resp_sof = digital_signal_alloc(160); + signals->nfcv_resp_sof = + digital_signal_alloc(slowdown * 27 + signals->nfcv_resp_one->edge_cnt); for(size_t i = 0; i < slowdown * 3; i++) { digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); } @@ -233,7 +234,8 @@ void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ } if(!signals->nfcv_resp_eof) { /* EOF: logic 0, 24 pulses, unmodulated */ - signals->nfcv_resp_eof = digital_signal_alloc(160); + signals->nfcv_resp_eof = + digital_signal_alloc(slowdown * 27 + signals->nfcv_resp_zero->edge_cnt); digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); for(size_t i = 0; i < slowdown * 24; i++) { digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); From 75d7246657664f82b5d70029c9bcc7fd1ce59f79 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Thu, 29 Dec 2022 22:38:13 +0100 Subject: [PATCH 046/216] ISO15693: further optimizations of allocation and free code --- lib/nfc/protocols/nfcv.c | 103 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 0f9a0b58a..69f179b4b 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -181,71 +181,71 @@ void nfcv_crc(uint8_t* data, uint32_t length) { } void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { - if(signals->nfcv_resp_one) { - digital_signal_free(signals->nfcv_resp_one); - signals->nfcv_resp_one = NULL; - } - if(signals->nfcv_resp_zero) { - digital_signal_free(signals->nfcv_resp_zero); - signals->nfcv_resp_zero = NULL; - } - if(signals->nfcv_resp_sof) { - digital_signal_free(signals->nfcv_resp_sof); - signals->nfcv_resp_sof = NULL; - } - if(signals->nfcv_resp_eof) { - digital_signal_free(signals->nfcv_resp_eof); - signals->nfcv_resp_eof = NULL; - } + digital_signal_free(signals->nfcv_resp_one); + digital_signal_free(signals->nfcv_resp_zero); + digital_signal_free(signals->nfcv_resp_sof); + digital_signal_free(signals->nfcv_resp_eof); + signals->nfcv_resp_one = NULL; + signals->nfcv_resp_zero = NULL; + signals->nfcv_resp_sof = NULL; + signals->nfcv_resp_eof = NULL; } -void nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { +bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { + bool ret = true; + if(!signals->nfcv_resp_one) { /* logical one: unmodulated then 8 pulses */ - signals->nfcv_resp_one = digital_signal_alloc(slowdown * 9); + signals->nfcv_resp_one = digital_signal_alloc( + slowdown * (air->nfcv_resp_unmod->edge_cnt + 8 * air->nfcv_resp_pulse->edge_cnt)); for(size_t i = 0; i < slowdown; i++) { - digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); + ret &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); } for(size_t i = 0; i < slowdown * 8; i++) { - digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); + ret &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); } } if(!signals->nfcv_resp_zero) { /* logical zero: 8 pulses then unmodulated */ - signals->nfcv_resp_zero = digital_signal_alloc(slowdown * 9); + signals->nfcv_resp_zero = digital_signal_alloc( + slowdown * (8 * air->nfcv_resp_pulse->edge_cnt + air->nfcv_resp_unmod->edge_cnt)); for(size_t i = 0; i < slowdown * 8; i++) { - digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); + ret &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); } for(size_t i = 0; i < slowdown; i++) { - digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); + ret &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); } } if(!signals->nfcv_resp_sof) { /* SOF: unmodulated, 24 pulses, logic 1 */ - signals->nfcv_resp_sof = - digital_signal_alloc(slowdown * 27 + signals->nfcv_resp_one->edge_cnt); + signals->nfcv_resp_sof = digital_signal_alloc( + slowdown * (3 * air->nfcv_resp_unmod->edge_cnt + 24 * air->nfcv_resp_pulse->edge_cnt) + + signals->nfcv_resp_one->edge_cnt); for(size_t i = 0; i < slowdown * 3; i++) { - digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); + ret &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); } for(size_t i = 0; i < slowdown * 24; i++) { - digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); + ret &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); } - digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); + ret &= digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); } if(!signals->nfcv_resp_eof) { /* EOF: logic 0, 24 pulses, unmodulated */ - signals->nfcv_resp_eof = - digital_signal_alloc(slowdown * 27 + signals->nfcv_resp_zero->edge_cnt); - digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); + signals->nfcv_resp_eof = digital_signal_alloc( + signals->nfcv_resp_zero->edge_cnt + + slowdown * (24 * air->nfcv_resp_pulse->edge_cnt + 3 * air->nfcv_resp_unmod->edge_cnt) + + air->nfcv_resp_unmod->edge_cnt); + ret &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); for(size_t i = 0; i < slowdown * 24; i++) { - digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); + ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); } for(size_t i = 0; i < slowdown * 3; i++) { - digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); } /* add extra silence */ - digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); } + return ret; } void nfcv_emu_alloc(NfcVData* nfcv_data) { @@ -272,8 +272,14 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { nfcv_data->emu_air.nfcv_resp_pulse->edge_cnt = 2; } - nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); - nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); + bool success = true; + + success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); + success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); + + if(!success) { + FURI_LOG_E(TAG, "Failed to allocate signals"); + } digital_sequence_set_signal( nfcv_data->emu_air.nfcv_signal, @@ -310,22 +316,15 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { } void nfcv_emu_free(NfcVData* nfcv_data) { - if(nfcv_data->emu_air.nfcv_resp_unmod) { - digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); - nfcv_data->emu_air.nfcv_resp_unmod = NULL; - } - if(nfcv_data->emu_air.nfcv_resp_pulse) { - digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); - nfcv_data->emu_air.nfcv_resp_pulse = NULL; - } - if(nfcv_data->emu_air.nfcv_signal) { - digital_sequence_free(nfcv_data->emu_air.nfcv_signal); - nfcv_data->emu_air.nfcv_signal = NULL; - } - if(nfcv_data->emu_air.reader_signal) { - pulse_reader_free(nfcv_data->emu_air.reader_signal); - nfcv_data->emu_air.reader_signal = NULL; - } + digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); + digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); + digital_sequence_free(nfcv_data->emu_air.nfcv_signal); + pulse_reader_free(nfcv_data->emu_air.reader_signal); + + nfcv_data->emu_air.nfcv_resp_unmod = NULL; + nfcv_data->emu_air.nfcv_resp_pulse = NULL; + nfcv_data->emu_air.nfcv_signal = NULL; + nfcv_data->emu_air.reader_signal = NULL; nfcv_emu_free_signals(&nfcv_data->emu_air.signals_high); nfcv_emu_free_signals(&nfcv_data->emu_air.signals_low); From 9f5a10a2e3a114622e11b44092317d0e034dad08 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 02:16:44 +0100 Subject: [PATCH 047/216] ISO15693: further cleanup --- .../main/nfc/helpers/nfc_custom_event.h | 2 + .../main/nfc/scenes/nfc_scene_nfcv_emulate.c | 22 +++++- lib/nfc/nfc_worker.c | 76 +++++++++---------- lib/nfc/nfc_worker.h | 4 +- lib/nfc/protocols/nfcv.c | 3 + lib/nfc/protocols/nfcv.h | 1 + lib/nfc/protocols/slix.c | 1 + 7 files changed, 62 insertions(+), 47 deletions(-) diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 4227a5b14..aa932a3d8 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -12,4 +12,6 @@ enum NfcCustomEvent { NfcCustomEventDictAttackSkip, NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, + NfcCustomEventUpdateLog, + NfcCustomEventSaveShadow, }; diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c index 53da36679..77d1d420d 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" -#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (100) +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200) enum { NfcSceneNfcVEmulateStateWidget, @@ -11,7 +11,17 @@ bool nfc_scene_nfcv_emulate_worker_callback(NfcWorkerEvent event, void* context) UNUSED(event); furi_assert(context); Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + + switch(event) { + case NfcWorkerEventNfcVCommandExecuted: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog); + break; + case NfcWorkerEventNfcVContentChanged: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow); + break; + default: + break; + } return true; } @@ -29,7 +39,6 @@ void nfc_scene_nfcv_emulate_textbox_callback(void* context) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -// Add widget with device name or inform that data received static void nfc_scene_nfcv_emulate_widget_config(Nfc* nfc, bool data_received) { FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; @@ -91,7 +100,7 @@ bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { + if(event.event == NfcCustomEventUpdateLog) { // Add data button to widget if data is received for the first time if(!furi_string_size(nfc->text_box_store)) { nfc_scene_nfcv_emulate_widget_config(nfc, true); @@ -111,6 +120,11 @@ bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) { strcpy(nfcv_data->last_command, ""); } consumed = true; + } else if(event.event == NfcCustomEventSaveShadow) { + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + consumed = true; } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVEmulateStateWidget) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 28ce057fc..b1f35c6cb 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -112,7 +112,7 @@ int32_t nfc_worker_task(void* context) { } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) { nfc_worker_analyze_reader(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVEmulate) { - nfc_worker_emulate_nfcv(nfc_worker); + nfc_worker_nfcv_emulate(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) { nfc_worker_nfcv_unlock(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { @@ -124,13 +124,15 @@ int32_t nfc_worker_task(void* context) { return 0; } -static bool nfc_worker_read_nfcv_content(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { +static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { bool read_success = false; NfcVReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + furi_hal_nfc_sleep(); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); @@ -150,6 +152,36 @@ static bool nfc_worker_read_nfcv_content(NfcWorker* nfc_worker, FuriHalNfcTxRxCo return read_success; } +void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + nfcv_emu_init(nfc_data, nfcv_data); + while(nfc_worker->state == NfcWorkerStateNfcVEmulate) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 50)) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context); + if(nfcv_data->modified) { + nfc_worker->callback(NfcWorkerEventNfcVContentChanged, nfc_worker->context); + nfcv_data->modified = false; + } + } + } + furi_delay_ms(0); + } + nfcv_emu_deinit(nfcv_data); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); @@ -439,20 +471,6 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t return card_read; } -static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { - furi_assert(nfc_worker); - furi_assert(tx_rx); - - bool card_read = false; - furi_hal_nfc_sleep(); - - /* until here the UID field is reversed from the reader IC. - we will read it here again and it will get placed in the right order. */ - card_read = nfc_worker_read_nfcv_content(nfc_worker, tx_rx); - - return card_read; -} - void nfc_worker_read(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); @@ -614,32 +632,6 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { } } -void nfc_worker_emulate_nfcv(NfcWorker* nfc_worker) { - FuriHalNfcTxRxContext tx_rx = {}; - FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); - reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); - } - - nfcv_emu_init(nfc_data, nfcv_data); - while(nfc_worker->state == NfcWorkerStateNfcVEmulate) { - if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 50)) { - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - } - furi_delay_ms(0); - } - nfcv_emu_deinit(nfcv_data); - - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - reader_analyzer_stop(nfc_worker->reader_analyzer); - } -} - void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcDevData params = { diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index 5113205c4..5b50139ee 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -74,6 +74,8 @@ typedef enum { NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key + NfcWorkerEventNfcVCommandExecuted, + NfcWorkerEventNfcVContentChanged, } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); @@ -93,4 +95,4 @@ void nfc_worker_start( void nfc_worker_stop(NfcWorker* nfc_worker); void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker); -void nfc_worker_emulate_nfcv(NfcWorker* nfc_worker); +void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker); diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 69f179b4b..66b14cbd3 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -561,6 +561,7 @@ void nfcv_emu_handle_packet( &nfcv_data->data[nfcv_data->block_size * block], &nfcv_data->frame[ctx->payload_offset + data_pos], data_len); + nfcv_data->modified = true; } nfcv_emu_send( tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); @@ -719,7 +720,9 @@ bool nfcv_emu_loop( pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); uint32_t timestamp = DWT->CYCCNT; + /* when timed out, reset to SOF state */ if(periods == PULSE_READER_NO_EDGE) { + frame_state = NFCV_FRAME_STATE_SOF1; break; } if(periods == PULSE_READER_LOST_EDGE) { diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 9d7a56326..c349b6e95 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -161,6 +161,7 @@ typedef struct { uint16_t block_num; uint8_t block_size; uint8_t data[NFCV_MAX_DUMP_SIZE]; + bool modified; /* specfic variant infos */ NfcVSubtype sub_type; diff --git a/lib/nfc/protocols/slix.c b/lib/nfc/protocols/slix.c index 6c6deacdd..eaa75509f 100644 --- a/lib/nfc/protocols/slix.c +++ b/lib/nfc/protocols/slix.c @@ -236,6 +236,7 @@ bool slix_generic_protocol_filter( break; case SLIX_PASS_PRIVACY: slix->privacy = false; + nfcv_data->modified = true; break; case SLIX_PASS_DESTROY: FURI_LOG_D(TAG, "Pooof! Got destroyed"); From a34a186bbab9a2cc36c21fc2b26a1961bb8befdf Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 30 Dec 2022 16:17:41 +0100 Subject: [PATCH 048/216] ISO15693: reduce latency on state machine reset --- lib/nfc/nfc_worker.c | 4 +-- lib/nfc/protocols/nfcv.c | 53 +++++++++++++--------------------------- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index b1f35c6cb..7291117a4 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -164,7 +164,7 @@ void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) { nfcv_emu_init(nfc_data, nfcv_data); while(nfc_worker->state == NfcWorkerStateNfcVEmulate) { - if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 50)) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) { if(nfc_worker->callback) { nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context); if(nfcv_data->modified) { @@ -173,7 +173,7 @@ void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) { } } } - furi_delay_ms(0); + furi_delay_ms(10); } nfcv_emu_deinit(nfcv_data); diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 66b14cbd3..136ff0db7 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -712,9 +712,11 @@ bool nfcv_emu_loop( uint32_t frame_pos = 0; uint32_t byte_value = 0; uint32_t bits_received = 0; - char reset_reason[128]; bool wait_for_pulse = false; + uint8_t period_buffer[256]; + uint32_t period_buffer_pos = 0; + while(true) { uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); @@ -729,15 +731,13 @@ bool nfcv_emu_loop( break; } + if(period_buffer_pos < sizeof(period_buffer)) { + period_buffer[period_buffer_pos++] = periods; + } + if(wait_for_pulse) { wait_for_pulse = false; if(periods != 1) { - snprintf( - reset_reason, - sizeof(reset_reason), - "SOF: Expected a single low pulse in state %lu, but got %lu", - frame_state, - periods); frame_state = NFCV_FRAME_STATE_RESET; } continue; @@ -764,23 +764,12 @@ bool nfcv_emu_loop( periods_previous = 2; wait_for_pulse = true; } else { - snprintf( - reset_reason, - sizeof(reset_reason), - "SOF: Expected 4/6 periods, got %lu", - periods); - frame_state = NFCV_FRAME_STATE_SOF1; + frame_state = NFCV_FRAME_STATE_RESET; } break; case NFCV_FRAME_STATE_CODING_256: if(periods_previous > periods) { - snprintf( - reset_reason, - sizeof(reset_reason), - "1oo256: Missing %lu periods from previous symbol, got %lu", - periods_previous, - periods); frame_state = NFCV_FRAME_STATE_RESET; break; } @@ -788,8 +777,6 @@ bool nfcv_emu_loop( periods -= periods_previous; if(periods > 512) { - snprintf( - reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods); frame_state = NFCV_FRAME_STATE_RESET; break; } @@ -809,13 +796,6 @@ bool nfcv_emu_loop( case NFCV_FRAME_STATE_CODING_4: if(periods_previous > periods) { - snprintf( - reset_reason, - sizeof(reset_reason), - "1oo4: Missing %lu periods from previous symbol, got %lu at pos %lu", - periods_previous, - periods, - frame_pos); frame_state = NFCV_FRAME_STATE_RESET; break; } @@ -843,12 +823,6 @@ bool nfcv_emu_loop( frame_state = NFCV_FRAME_STATE_EOF; break; } else { - snprintf( - reset_reason, - sizeof(reset_reason), - "1oo4: Expected 1/3/5/7 low pulses, but got %lu at pos %lu", - periods, - frame_pos); frame_state = NFCV_FRAME_STATE_RESET; break; } @@ -864,8 +838,6 @@ bool nfcv_emu_loop( /* post-state-machine cleanup and reset */ if(frame_state == NFCV_FRAME_STATE_RESET) { frame_state = NFCV_FRAME_STATE_SOF1; - - FURI_LOG_D(TAG, "Resetting state machine, reason: '%s'", reset_reason); } else if(frame_state == NFCV_FRAME_STATE_EOF) { nfcv_data->frame = frame_payload; nfcv_data->frame_length = frame_pos; @@ -883,6 +855,15 @@ bool nfcv_emu_loop( nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); pulse_reader_start(nfcv_data->emu_air.reader_signal); ret = true; + } else { + if(frame_state != NFCV_FRAME_STATE_SOF1) { + FURI_LOG_T(TAG, "leaving while in state: %lu", frame_state); + } + } + + FURI_LOG_T(TAG, "pulses:"); + for(uint32_t pos = 0; pos < period_buffer_pos; pos++) { + FURI_LOG_T(TAG, " #%lu: %u", pos, period_buffer[pos]); } return ret; From fecc686a3e18f43b252972f2066951c3a323b6b8 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Tue, 3 Jan 2023 01:27:34 +0100 Subject: [PATCH 049/216] further code cleanups --- lib/nfc/protocols/nfcv.c | 72 +++++++++++++++++++++++++++++----------- lib/nfc/protocols/nfcv.h | 18 ++++++---- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 136ff0db7..cc7f4ad59 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -181,6 +181,8 @@ void nfcv_crc(uint8_t* data, uint32_t length) { } void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { + furi_assert(signals); + digital_signal_free(signals->nfcv_resp_one); digital_signal_free(signals->nfcv_resp_zero); digital_signal_free(signals->nfcv_resp_sof); @@ -192,6 +194,9 @@ void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { } bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { + furi_assert(air); + furi_assert(signals); + bool ret = true; if(!signals->nfcv_resp_one) { @@ -249,6 +254,8 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ } void nfcv_emu_alloc(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + if(!nfcv_data->emu_air.nfcv_signal) { /* assuming max frame length is 255 bytes */ nfcv_data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); @@ -316,6 +323,8 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { } void nfcv_emu_free(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); digital_sequence_free(nfcv_data->emu_air.nfcv_signal); @@ -337,6 +346,9 @@ void nfcv_emu_send( uint8_t length, NfcVSendFlags flags, uint32_t send_time) { + furi_assert(tx_rx); + furi_assert(nfcv); + /* picked default value (0) to match the most common format */ if(!flags) { flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | @@ -402,6 +414,10 @@ void nfcv_emu_handle_packet( FuriHalNfcTxRxContext* tx_rx, FuriHalNfcDevData* nfc_data, void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; @@ -618,7 +634,11 @@ void nfcv_emu_handle_packet( } void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + furi_assert(nfc_data); + furi_assert(nfcv_data); + nfcv_emu_alloc(nfcv_data); + rfal_platform_spi_acquire(); /* configure for transparent and passive mode */ st25r3916ExecuteCommand(ST25R3916_CMD_STOP); @@ -626,7 +646,7 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3); /* target mode: ISO14443 passive mode */ st25r3916WriteRegister(ST25R3916_REG_MODE, 0x88); - /* let us modulate the field using MOSI, read modulation using MISO */ + /* let us modulate the field using MOSI, read ASK modulation using IRQ */ st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); @@ -686,6 +706,8 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { } void nfcv_emu_deinit(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); rfal_platform_spi_release(); nfcv_emu_free(nfcv_data); @@ -705,36 +727,40 @@ bool nfcv_emu_loop( FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data); + bool ret = false; uint32_t frame_state = NFCV_FRAME_STATE_SOF1; uint32_t periods_previous = 0; - uint8_t frame_payload[128]; uint32_t frame_pos = 0; uint32_t byte_value = 0; uint32_t bits_received = 0; + uint32_t timeout = timeout_ms * 1000; bool wait_for_pulse = false; - uint8_t period_buffer[256]; +#ifdef NFCV_DIAGNOSTIC_DUMPS + uint8_t period_buffer[NFCV_DIAGNOSTIC_DUMP_SIZE]; uint32_t period_buffer_pos = 0; +#endif while(true) { - uint32_t periods = - pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout_ms * 1000); + uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout); uint32_t timestamp = DWT->CYCCNT; /* when timed out, reset to SOF state */ - if(periods == PULSE_READER_NO_EDGE) { - frame_state = NFCV_FRAME_STATE_SOF1; - break; - } - if(periods == PULSE_READER_LOST_EDGE) { + if(periods == PULSE_READER_NO_EDGE || periods == PULSE_READER_LOST_EDGE) { break; } +#ifdef NFCV_DIAGNOSTIC_DUMPS if(period_buffer_pos < sizeof(period_buffer)) { period_buffer[period_buffer_pos++] = periods; } +#endif + /* short helper for detecting a pulse position */ if(wait_for_pulse) { wait_for_pulse = false; if(periods != 1) { @@ -773,22 +799,23 @@ bool nfcv_emu_loop( frame_state = NFCV_FRAME_STATE_RESET; break; } + /* previous symbol left us with some pulse periods */ periods -= periods_previous; if(periods > 512) { frame_state = NFCV_FRAME_STATE_RESET; break; - } - - if(periods == 2) { + } else if(periods == 2) { frame_state = NFCV_FRAME_STATE_EOF; break; } periods_previous = 512 - (periods + 1); byte_value = (periods - 1) / 2; - frame_payload[frame_pos++] = (uint8_t)byte_value; + if(frame_pos < NFCV_MAX_FRAME_SIZE) { + nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; + } wait_for_pulse = true; @@ -828,7 +855,9 @@ bool nfcv_emu_loop( } if(bits_received >= 8) { - frame_payload[frame_pos++] = (uint8_t)byte_value; + if(frame_pos < NFCV_MAX_FRAME_SIZE) { + nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; + } bits_received = 0; } wait_for_pulse = true; @@ -839,7 +868,6 @@ bool nfcv_emu_loop( if(frame_state == NFCV_FRAME_STATE_RESET) { frame_state = NFCV_FRAME_STATE_SOF1; } else if(frame_state == NFCV_FRAME_STATE_EOF) { - nfcv_data->frame = frame_payload; nfcv_data->frame_length = frame_pos; nfcv_data->eof_timestamp = timestamp; break; @@ -850,7 +878,7 @@ bool nfcv_emu_loop( /* we know that this code uses TIM2, so stop pulse reader */ pulse_reader_stop(nfcv_data->emu_air.reader_signal); if(tx_rx->sniff_rx) { - tx_rx->sniff_rx(frame_payload, frame_pos * 8, false, tx_rx->sniff_context); + tx_rx->sniff_rx(nfcv_data->frame, frame_pos * 8, false, tx_rx->sniff_context); } nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); pulse_reader_start(nfcv_data->emu_air.reader_signal); @@ -861,10 +889,14 @@ bool nfcv_emu_loop( } } - FURI_LOG_T(TAG, "pulses:"); - for(uint32_t pos = 0; pos < period_buffer_pos; pos++) { - FURI_LOG_T(TAG, " #%lu: %u", pos, period_buffer[pos]); +#ifdef NFCV_DIAGNOSTIC_DUMPS + if(period_buffer_pos) { + FURI_LOG_T(TAG, "pulses:"); + for(uint32_t pos = 0; pos < period_buffer_pos; pos++) { + FURI_LOG_T(TAG, " #%lu: %u", pos, period_buffer[pos]); + } } +#endif return ret; } diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index c349b6e95..266b84ed8 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -16,7 +16,7 @@ extern "C" { #define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */ #define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */ -#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC) /* ns */ +#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC) #define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) #define DIGITAL_SIGNAL_UNIT_US (100000.0f) @@ -24,6 +24,11 @@ extern "C" { #define NFCV_TOTAL_BLOCKS_MAX 256 #define NFCV_BLOCK_SIZE 4 #define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE * NFCV_TOTAL_BLOCKS_MAX) +#define NFCV_MAX_FRAME_SIZE 64 +#define NFCV_LOG_STR_LEN 128 + +// #define NFCV_DIAGNOSTIC_DUMPS +// #define NFCV_DIAGNOSTIC_DUMP_SIZE 128 /* helpers to calculate the send time based on DWT->CYCCNT */ #define NFCV_FDT_USEC(usec) (usec * 64) @@ -138,6 +143,7 @@ typedef bool (*NfcVEmuProtocolFilter)( FuriHalNfcDevData* nfc_data, void* nfcv_data); +/* the default ISO15693 handler context */ typedef struct { uint8_t flags; /* ISO15693-3 flags of the header as specified */ uint8_t command; /* ISO15693-3 command at offset 1 as specified */ @@ -146,7 +152,7 @@ typedef struct { uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ - uint8_t response_buffer[128]; /* pre-allocated response buffer */ + uint8_t response_buffer[NFCV_MAX_FRAME_SIZE]; /* pre-allocated response buffer */ NfcVSendFlags response_flags; /* flags to use when sending response */ uint32_t send_time; /* timestamp when to send the response */ @@ -161,6 +167,7 @@ typedef struct { uint16_t block_num; uint8_t block_size; uint8_t data[NFCV_MAX_DUMP_SIZE]; + bool modified; /* specfic variant infos */ @@ -171,17 +178,16 @@ typedef struct { /* precalced air level data */ NfcVEmuAir emu_air; - uint8_t* frame; /* ISO15693-2 incoming raw data from air layer */ + uint8_t frame[NFCV_MAX_FRAME_SIZE]; /* ISO15693-2 incoming raw data from air layer */ uint8_t frame_length; /* ISO15693-2 length of incoming data */ uint32_t eof_timestamp; /* ISO15693-2 EOF timestamp, read from DWT->CYCCNT */ /* handler for the protocol layer as specified in ISO15693-3 */ NfcVEmuProtocolHandler emu_protocol_handler; void* emu_protocol_ctx; - /* runtime data */ - char last_command[128]; - char error[32]; + char last_command[NFCV_LOG_STR_LEN]; + char error[NFCV_LOG_STR_LEN]; } NfcVData; typedef struct { From aa7ead724aecde1bd4a065553a3c5d30e1c9ba93 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 20 Jan 2023 01:34:15 +0100 Subject: [PATCH 050/216] respond with block security status when option flag is set --- lib/nfc/protocols/nfcv.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index cc7f4ad59..90752fe98 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -537,20 +537,32 @@ void nfcv_emu_handle_packet( nfcv_emu_send( tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); } else { - ctx->response_buffer[0] = ISO15693_NOERROR; - memcpy( - &ctx->response_buffer[1], - &nfcv_data->data[nfcv_data->block_size * block], - nfcv_data->block_size * blocks); + uint8_t buffer_pos = 0; + + ctx->response_buffer[buffer_pos++] = ISO15693_NOERROR; + + for(int current_block = 0; current_block < blocks; current_block++) { + /* prepend security status */ + if(ctx->flags & RFAL_NFCV_REQ_FLAG_OPTION) { + ctx->response_buffer[buffer_pos++] = 0; + } + /* then the data block */ + memcpy( + &ctx->response_buffer[buffer_pos], + &nfcv_data->data[nfcv_data->block_size * (block + current_block)], + nfcv_data->block_size); + buffer_pos += nfcv_data->block_size; + } nfcv_emu_send( tx_rx, nfcv_data, ctx->response_buffer, - 1 + nfcv_data->block_size * blocks, + buffer_pos, ctx->response_flags, ctx->send_time); } snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); + break; } From f03d31b647d9de93161485ed8d239d89e1197a1d Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Fri, 20 Jan 2023 23:29:34 +0100 Subject: [PATCH 051/216] increased maximum memory size to match standard added security status handling/load/save added SELECT/QUIET handling more fine grained allocation routines and checks fix memset sizes --- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 3 +- .../main/nfc/scenes/nfc_scene_nfcv_emulate.c | 7 +- lib/nfc/nfc_device.c | 20 +- lib/nfc/protocols/nfcv.c | 175 ++++++++++++++---- lib/nfc/protocols/nfcv.h | 24 ++- 5 files changed, 177 insertions(+), 52 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 88df6705c..87a23c8ef 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -103,11 +103,12 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } for(int block = 0; block < maxBlocks; block++) { + const char* status = (nfcv_data->security_status[block] & 0x01) ? "(lck)" : ""; for(int pos = 0; pos < nfcv_data->block_size; pos++) { furi_string_cat_printf( temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]); } - furi_string_cat_printf(temp_str, "\n"); + furi_string_cat_printf(temp_str, " %s\n", status); } furi_string_cat_printf(temp_str, "\n"); diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c index 77d1d420d..ca10f5d6e 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_emulate.c @@ -75,6 +75,7 @@ void nfc_scene_nfcv_emulate_on_enter(void* context) { TextBox* text_box = nfc->text_box; text_box_set_font(text_box, TextBoxFontHex); text_box_set_focus(text_box, TextBoxFocusEnd); + text_box_set_text(text_box, ""); furi_string_reset(nfc->text_box_store); // Set Widget state and view @@ -102,10 +103,10 @@ bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventUpdateLog) { // Add data button to widget if data is received for the first time - if(!furi_string_size(nfc->text_box_store)) { - nfc_scene_nfcv_emulate_widget_config(nfc, true); - } if(strlen(nfcv_data->last_command) > 0) { + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_nfcv_emulate_widget_config(nfc, true); + } /* use the last n bytes from the log so there's enough space for the new log entry */ size_t maxSize = NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index b925d651e..3a3b69344 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -674,7 +674,7 @@ static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; - memset(data, 0, sizeof(NfcVData)); + memset(data, 0, sizeof(NfcVSlixData)); do { if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) @@ -715,7 +715,7 @@ static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; - memset(data, 0, sizeof(NfcVData)); + memset(data, 0, sizeof(NfcVSlixData)); do { if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) @@ -763,7 +763,7 @@ static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; - memset(data, 0, sizeof(NfcVData)); + memset(data, 0, sizeof(NfcVSlixData)); do { if(!flipper_format_read_hex( @@ -811,7 +811,7 @@ static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; - memset(data, 0, sizeof(NfcVData)); + memset(data, 0, sizeof(NfcVSlixData)); do { if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) @@ -858,6 +858,9 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { if(!flipper_format_write_hex( file, "Data Content", data->data, data->block_num * data->block_size)) break; + if(!flipper_format_write_hex( + file, "Security Status", data->security_status, data->block_num)) + break; if(!flipper_format_write_comment_cstr( file, "Subtype of this card (0 = ISO15693, 1 = SLIX, 2 = SLIX-S, 3 = SLIX-L, 4 = SLIX2)")) @@ -892,7 +895,7 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; NfcVData* data = &dev->dev_data.nfcv_data; - memset(data, 0, sizeof(NfcVData)); + memset(data, 0x00, sizeof(NfcVData)); do { uint32_t temp_uint32 = 0; @@ -907,6 +910,13 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { if(!flipper_format_read_hex( file, "Data Content", data->data, data->block_num * data->block_size)) break; + + /* optional, as added later */ + if(flipper_format_key_exist(file, "Security Status")) { + if(!flipper_format_read_hex( + file, "Security Status", data->security_status, data->block_num)) + break; + } if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break; data->sub_type = temp_value; diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 90752fe98..dc37860fb 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -183,10 +183,18 @@ void nfcv_crc(uint8_t* data, uint32_t length) { void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { furi_assert(signals); - digital_signal_free(signals->nfcv_resp_one); - digital_signal_free(signals->nfcv_resp_zero); - digital_signal_free(signals->nfcv_resp_sof); - digital_signal_free(signals->nfcv_resp_eof); + if(signals->nfcv_resp_one) { + digital_signal_free(signals->nfcv_resp_one); + } + if(signals->nfcv_resp_zero) { + digital_signal_free(signals->nfcv_resp_zero); + } + if(signals->nfcv_resp_sof) { + digital_signal_free(signals->nfcv_resp_sof); + } + if(signals->nfcv_resp_eof) { + digital_signal_free(signals->nfcv_resp_eof); + } signals->nfcv_resp_one = NULL; signals->nfcv_resp_zero = NULL; signals->nfcv_resp_sof = NULL; @@ -197,28 +205,40 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ furi_assert(air); furi_assert(signals); - bool ret = true; + bool success = true; if(!signals->nfcv_resp_one) { /* logical one: unmodulated then 8 pulses */ signals->nfcv_resp_one = digital_signal_alloc( slowdown * (air->nfcv_resp_unmod->edge_cnt + 8 * air->nfcv_resp_pulse->edge_cnt)); + if(!signals->nfcv_resp_one) { + return false; + } for(size_t i = 0; i < slowdown; i++) { - ret &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); + success &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); } for(size_t i = 0; i < slowdown * 8; i++) { - ret &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); + success &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); + } + if(!success) { + return false; } } if(!signals->nfcv_resp_zero) { /* logical zero: 8 pulses then unmodulated */ signals->nfcv_resp_zero = digital_signal_alloc( slowdown * (8 * air->nfcv_resp_pulse->edge_cnt + air->nfcv_resp_unmod->edge_cnt)); + if(!signals->nfcv_resp_zero) { + return false; + } for(size_t i = 0; i < slowdown * 8; i++) { - ret &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); + success &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); } for(size_t i = 0; i < slowdown; i++) { - ret &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); + success &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); + } + if(!success) { + return false; } } if(!signals->nfcv_resp_sof) { @@ -226,13 +246,19 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ signals->nfcv_resp_sof = digital_signal_alloc( slowdown * (3 * air->nfcv_resp_unmod->edge_cnt + 24 * air->nfcv_resp_pulse->edge_cnt) + signals->nfcv_resp_one->edge_cnt); + if(!signals->nfcv_resp_sof) { + return false; + } for(size_t i = 0; i < slowdown * 3; i++) { - ret &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); + success &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); } for(size_t i = 0; i < slowdown * 24; i++) { - ret &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); + success &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); + } + success &= digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); + if(!success) { + return false; } - ret &= digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); } if(!signals->nfcv_resp_eof) { /* EOF: logic 0, 24 pulses, unmodulated */ @@ -240,29 +266,48 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ signals->nfcv_resp_zero->edge_cnt + slowdown * (24 * air->nfcv_resp_pulse->edge_cnt + 3 * air->nfcv_resp_unmod->edge_cnt) + air->nfcv_resp_unmod->edge_cnt); - ret &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); + if(!signals->nfcv_resp_eof) { + return false; + } + success &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); for(size_t i = 0; i < slowdown * 24; i++) { - ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); } for(size_t i = 0; i < slowdown * 3; i++) { - ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); } /* add extra silence */ - ret &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); + if(!success) { + return false; + } } - return ret; + return success; } -void nfcv_emu_alloc(NfcVData* nfcv_data) { +bool nfcv_emu_alloc(NfcVData* nfcv_data) { furi_assert(nfcv_data); + if(!nfcv_data->frame) { + nfcv_data->frame = malloc(NFCV_FRAMESIZE_MAX); + if(!nfcv_data->frame) { + return false; + } + } + if(!nfcv_data->emu_air.nfcv_signal) { /* assuming max frame length is 255 bytes */ nfcv_data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); + if(!nfcv_data->emu_air.nfcv_signal) { + return false; + } } if(!nfcv_data->emu_air.nfcv_resp_unmod) { /* unmodulated 256/fc or 1024/fc signal as building block */ nfcv_data->emu_air.nfcv_resp_unmod = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_unmod) { + return false; + } nfcv_data->emu_air.nfcv_resp_unmod->start_level = false; nfcv_data->emu_air.nfcv_resp_unmod->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); @@ -271,6 +316,9 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { if(!nfcv_data->emu_air.nfcv_resp_pulse) { /* modulated fc/32 or fc/8 pulse as building block */ nfcv_data->emu_air.nfcv_resp_pulse = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_pulse) { + return false; + } nfcv_data->emu_air.nfcv_resp_pulse->start_level = true; nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); @@ -280,12 +328,12 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { } bool success = true; - success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); if(!success) { FURI_LOG_E(TAG, "Failed to allocate signals"); + return false; } digital_sequence_set_signal( @@ -320,16 +368,33 @@ void nfcv_emu_alloc(NfcVData* nfcv_data) { nfcv_data->emu_air.nfcv_signal, NFCV_SIG_LOW_EOF, nfcv_data->emu_air.signals_low.nfcv_resp_eof); + + return true; } void nfcv_emu_free(NfcVData* nfcv_data) { furi_assert(nfcv_data); - digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); - digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); - digital_sequence_free(nfcv_data->emu_air.nfcv_signal); - pulse_reader_free(nfcv_data->emu_air.reader_signal); + if(nfcv_data->frame) { + free(nfcv_data->frame); + } + if(nfcv_data->emu_protocol_ctx) { + free(nfcv_data->emu_protocol_ctx); + } + if(nfcv_data->emu_air.nfcv_resp_unmod) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); + } + if(nfcv_data->emu_air.nfcv_resp_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); + } + if(nfcv_data->emu_air.nfcv_signal) { + digital_sequence_free(nfcv_data->emu_air.nfcv_signal); + } + if(nfcv_data->emu_air.reader_signal) { + pulse_reader_free(nfcv_data->emu_air.reader_signal); + } + nfcv_data->frame = NULL; nfcv_data->emu_air.nfcv_resp_unmod = NULL; nfcv_data->emu_air.nfcv_resp_pulse = NULL; nfcv_data->emu_air.nfcv_signal = NULL; @@ -428,6 +493,7 @@ void nfcv_emu_handle_packet( /* parse the frame data for the upcoming part 3 handling */ ctx->flags = nfcv_data->frame[0]; ctx->command = nfcv_data->frame[1]; + ctx->selected = (ctx->flags & RFAL_NFCV_REQ_FLAG_SELECT); ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); ctx->advanced = (ctx->command >= 0xA0); @@ -474,6 +540,14 @@ void nfcv_emu_handle_packet( } } + if(ctx->selected && !nfcv_data->selected) { + FURI_LOG_D( + TAG, + "selected card shall execute command 0x%02X, but we were not selected", + ctx->command); + return; + } + /* then give control to the card subtype specific protocol filter */ if(ctx->emu_protocol_filter != NULL) { if(ctx->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) { @@ -487,28 +561,39 @@ void nfcv_emu_handle_packet( switch(ctx->command) { case ISO15693_INVENTORY: { - ctx->response_buffer[0] = ISO15693_NOERROR; - ctx->response_buffer[1] = nfcv_data->dsfid; - nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid); + if(!nfcv_data->quiet) { + ctx->response_buffer[0] = ISO15693_NOERROR; + ctx->response_buffer[1] = nfcv_data->dsfid; + nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid); - nfcv_emu_send( - tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags, ctx->send_time); - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + } else { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY (quiet)"); + } break; } case ISO15693_STAYQUIET: { snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET"); + nfcv_data->quiet = true; break; } case ISO15693_LOCKBLOCK: { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK"); + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + nfcv_data->security_status[block] |= 0x01; + nfcv_data->modified = true; + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK BLOCK %d", block); break; } case ISO15693_SELECT: { ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_data->selected = true; + nfcv_data->quiet = false; nfcv_emu_send( tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); @@ -517,6 +602,7 @@ void nfcv_emu_handle_packet( case ISO15693_RESET_TO_READY: { ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_data->quiet = false; nfcv_emu_send( tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "RESET_TO_READY"); @@ -541,15 +627,16 @@ void nfcv_emu_handle_packet( ctx->response_buffer[buffer_pos++] = ISO15693_NOERROR; - for(int current_block = 0; current_block < blocks; current_block++) { + for(int block_index = 0; block_index < blocks; block_index++) { + int block_current = block + block_index; /* prepend security status */ if(ctx->flags & RFAL_NFCV_REQ_FLAG_OPTION) { - ctx->response_buffer[buffer_pos++] = 0; + ctx->response_buffer[buffer_pos++] = nfcv_data->security_status[block_current]; } /* then the data block */ memcpy( &ctx->response_buffer[buffer_pos], - &nfcv_data->data[nfcv_data->block_size * (block + current_block)], + &nfcv_data->data[nfcv_data->block_size * block_current], nfcv_data->block_size); buffer_pos += nfcv_data->block_size; } @@ -649,7 +736,19 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { furi_assert(nfc_data); furi_assert(nfcv_data); - nfcv_emu_alloc(nfcv_data); + if(!nfcv_emu_alloc(nfcv_data)) { + FURI_LOG_E(TAG, "Failed to allocate structures"); + nfcv_data->ready = false; + return; + } + + strcpy(nfcv_data->last_command, ""); + nfcv_data->quiet = false; + nfcv_data->selected = false; + nfcv_data->modified = false; + + /* everything is initialized */ + nfcv_data->ready = true; rfal_platform_spi_acquire(); /* configure for transparent and passive mode */ @@ -752,6 +851,10 @@ bool nfcv_emu_loop( uint32_t timeout = timeout_ms * 1000; bool wait_for_pulse = false; + if(!nfcv_data->ready) { + return false; + } + #ifdef NFCV_DIAGNOSTIC_DUMPS uint8_t period_buffer[NFCV_DIAGNOSTIC_DUMP_SIZE]; uint32_t period_buffer_pos = 0; @@ -825,7 +928,7 @@ bool nfcv_emu_loop( periods_previous = 512 - (periods + 1); byte_value = (periods - 1) / 2; - if(frame_pos < NFCV_MAX_FRAME_SIZE) { + if(frame_pos < NFCV_FRAMESIZE_MAX) { nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; } @@ -867,7 +970,7 @@ bool nfcv_emu_loop( } if(bits_received >= 8) { - if(frame_pos < NFCV_MAX_FRAME_SIZE) { + if(frame_pos < NFCV_FRAMESIZE_MAX) { nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; } bits_received = 0; diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 266b84ed8..3f8e78556 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -21,10 +21,15 @@ extern "C" { #define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) #define DIGITAL_SIGNAL_UNIT_US (100000.0f) -#define NFCV_TOTAL_BLOCKS_MAX 256 -#define NFCV_BLOCK_SIZE 4 -#define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE * NFCV_TOTAL_BLOCKS_MAX) -#define NFCV_MAX_FRAME_SIZE 64 +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */ +#define NFCV_BLOCKS_MAX 256 +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum size of blocks is defined as 32 */ +#define NFCV_BLOCKSIZE_MAX 32 +/* the resulting memory size a card can have */ +#define NFCV_MEMSIZE_MAX (NFCV_BLOCKS_MAX * NFCV_BLOCKSIZE_MAX) +/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */ +#define NFCV_FRAMESIZE_MAX (1 + NFCV_MEMSIZE_MAX + NFCV_BLOCKS_MAX) + #define NFCV_LOG_STR_LEN 128 // #define NFCV_DIAGNOSTIC_DUMPS @@ -147,12 +152,13 @@ typedef bool (*NfcVEmuProtocolFilter)( typedef struct { uint8_t flags; /* ISO15693-3 flags of the header as specified */ uint8_t command; /* ISO15693-3 command at offset 1 as specified */ + bool selected; /* ISO15693-3 flags: selected frame */ bool addressed; /* ISO15693-3 flags: addressed frame */ bool advanced; /* ISO15693-3 command: advanced command */ uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ - uint8_t response_buffer[NFCV_MAX_FRAME_SIZE]; /* pre-allocated response buffer */ + uint8_t response_buffer[NFCV_FRAMESIZE_MAX]; /* pre-allocated response buffer */ NfcVSendFlags response_flags; /* flags to use when sending response */ uint32_t send_time; /* timestamp when to send the response */ @@ -166,9 +172,13 @@ typedef struct { uint8_t ic_ref; uint16_t block_num; uint8_t block_size; - uint8_t data[NFCV_MAX_DUMP_SIZE]; + uint8_t data[NFCV_MEMSIZE_MAX]; + uint8_t security_status[NFCV_BLOCKS_MAX]; + bool selected; + bool quiet; bool modified; + bool ready; /* specfic variant infos */ NfcVSubtype sub_type; @@ -178,7 +188,7 @@ typedef struct { /* precalced air level data */ NfcVEmuAir emu_air; - uint8_t frame[NFCV_MAX_FRAME_SIZE]; /* ISO15693-2 incoming raw data from air layer */ + uint8_t* frame; /* [NFCV_FRAMESIZE_MAX] ISO15693-2 incoming raw data from air layer */ uint8_t frame_length; /* ISO15693-2 length of incoming data */ uint32_t eof_timestamp; /* ISO15693-2 EOF timestamp, read from DWT->CYCCNT */ From 4f4eca1dd7bc471b60bbd89c649c261656e7b748 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 21 Jan 2023 01:04:02 +0100 Subject: [PATCH 052/216] added "Listen NfcV Reader" to sniff traffic from reader to card --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 10 ++ .../main/nfc/scenes/nfc_scene_nfcv_sniff.c | 155 +++++++++++++++++ lib/nfc/nfc_device.c | 4 + lib/nfc/nfc_worker.c | 30 ++++ lib/nfc/nfc_worker.h | 2 + lib/nfc/protocols/nfcv.c | 163 +++++++++++++++++- lib/nfc/protocols/nfcv.h | 1 + 8 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index b4d5a6e1d..d6edebe73 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -19,6 +19,7 @@ ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate) +ADD_SCENE(nfc, nfcv_sniff, NfcVSniff) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 9560768a5..7f5bc7e75 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -5,6 +5,7 @@ enum SubmenuIndex { SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, SubmenuIndexNfcVUnlock, + SubmenuIndexNfcVSniff, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { @@ -41,6 +42,12 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexNfcVUnlock, nfc_scene_extra_actions_submenu_callback, nfc); + submenu_add_item( + submenu, + "Listen NfcV Reader", + SubmenuIndexNfcVSniff, + nfc_scene_extra_actions_submenu_callback, + nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); @@ -68,6 +75,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexNfcVUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu); consumed = true; + } else if(event.event == SubmenuIndexNfcVSniff) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c b/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c new file mode 100644 index 000000000..b2cb58d9f --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c @@ -0,0 +1,155 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200) + +enum { + NfcSceneNfcVSniffStateWidget, + NfcSceneNfcVSniffStateTextBox, +}; + +bool nfc_scene_nfcv_sniff_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + Nfc* nfc = context; + + switch(event) { + case NfcWorkerEventNfcVCommandExecuted: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog); + break; + case NfcWorkerEventNfcVContentChanged: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow); + break; + default: + break; + } + return true; +} + +void nfc_scene_nfcv_sniff_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfcv_sniff_textbox_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +static void nfc_scene_nfcv_sniff_widget_config(Nfc* nfc, bool data_received) { + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); + widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Listen NfcV"); + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_sniff_widget_callback, nfc); + } +} + +void nfc_scene_nfcv_sniff_on_enter(void* context) { + Nfc* nfc = context; + + // Setup Widget + nfc_scene_nfcv_sniff_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + text_box_set_text(text_box, ""); + furi_string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVSniff, + &nfc->dev->dev_data, + nfc_scene_nfcv_sniff_worker_callback, + nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_nfcv_sniff_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVSniff); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventUpdateLog) { + // Add data button to widget if data is received for the first time + if(strlen(nfcv_data->last_command) > 0) { + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_nfcv_sniff_widget_config(nfc, true); + } + /* use the last n bytes from the log so there's enough space for the new log entry */ + size_t maxSize = + NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); + if(furi_string_size(nfc->text_box_store) >= maxSize) { + furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1)); + } + furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command); + furi_string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + + /* clear previously logged command */ + strcpy(nfcv_data->last_command, ""); + } + consumed = true; + } else if(event.event == NfcCustomEventSaveShadow) { + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVSniffStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVSniffStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneNfcVSniffStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_nfcv_sniff_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 3a3b69344..0aec74f0f 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -885,6 +885,8 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { case NfcVTypeSlix2: saved = nfc_device_save_slix2_data(file, dev); break; + default: + break; } } while(false); @@ -936,6 +938,8 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { case NfcVTypeSlix2: parsed = nfc_device_load_slix2_data(file, dev); break; + default: + break; } } while(false); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 7291117a4..753bba00a 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -113,6 +113,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_analyze_reader(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVEmulate) { nfc_worker_nfcv_emulate(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVSniff) { + nfc_worker_nfcv_sniff(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) { nfc_worker_nfcv_unlock(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { @@ -182,6 +184,34 @@ void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) { } } +void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + nfcv_data->sub_type = NfcVTypeSniff; + nfcv_emu_init(nfc_data, nfcv_data); + + while(nfc_worker->state == NfcWorkerStateNfcVSniff) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context); + } + } + furi_delay_ms(10); + } + nfcv_emu_deinit(nfcv_data); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index 5b50139ee..722f14857 100644 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -21,6 +21,7 @@ typedef enum { NfcWorkerStateNfcVEmulate, NfcWorkerStateNfcVUnlock, NfcWorkerStateNfcVUnlockAndSave, + NfcWorkerStateNfcVSniff, // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, @@ -96,3 +97,4 @@ void nfc_worker_start( void nfc_worker_stop(NfcWorker* nfc_worker); void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker); void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker); +void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker); \ No newline at end of file diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index dc37860fb..c9982f156 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -732,6 +732,160 @@ void nfcv_emu_handle_packet( } } +void nfcv_emu_sniff_packet( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + + if(nfcv_data->frame_length < 2) { + return; + } + + /* parse the frame data for the upcoming part 3 handling */ + ctx->flags = nfcv_data->frame[0]; + ctx->command = nfcv_data->frame[1]; + ctx->selected = (ctx->flags & RFAL_NFCV_REQ_FLAG_SELECT); + ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && + (ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS); + ctx->advanced = (ctx->command >= 0xA0); + ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); + ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); + + char flags_string[5]; + + snprintf( + flags_string, + 5, + "%c%c%c%d", + (ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) ? + 'I' : + (ctx->addressed ? 'A' : (ctx->selected ? 'S' : '*')), + ctx->advanced ? 'X' : ' ', + (ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) ? 'h' : 'l', + (ctx->flags & RFAL_NFCV_REQ_FLAG_SUB_CARRIER) ? 2 : 1); + + switch(ctx->command) { + case ISO15693_INVENTORY: { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + break; + } + + case ISO15693_STAYQUIET: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s STAYQUIET", flags_string); + nfcv_data->quiet = true; + break; + } + + case ISO15693_LOCKBLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s LOCK %d", + flags_string, + block); + break; + } + + case ISO15693_SELECT: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s SELECT", flags_string); + break; + } + + case ISO15693_RESET_TO_READY: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s RESET", flags_string); + break; + } + + case ISO15693_READ_MULTI_BLOCK: + case ISO15693_READBLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + + if(ctx->command == ISO15693_READ_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + } + + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s READ %d cnt: %d", + flags_string, + block, + blocks); + + break; + } + + case ISO15693_WRITE_MULTI_BLOCK: + case ISO15693_WRITEBLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + uint8_t data_pos = 1; + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + data_pos++; + } + + uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos]; + + if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WRITE %d, cnd %d", + flags_string, + block, + blocks); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WRITE %d %02X %02X %02X %02X", + flags_string, + block, + data[0], + data[1], + data[2], + data[3]); + } + break; + } + + case ISO15693_GET_SYSTEM_INFO: { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s SYSTEMINFO", + flags_string); + break; + } + + default: + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s unsupported: %02X", + flags_string, + ctx->command); + break; + } + + if(strlen(nfcv_data->last_command) > 0) { + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); + } +} + void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { furi_assert(nfc_data); furi_assert(nfcv_data); @@ -765,7 +919,11 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { /* if not set already, initialize the default protocol handler */ if(!nfcv_data->emu_protocol_ctx) { nfcv_data->emu_protocol_ctx = malloc(sizeof(NfcVEmuProtocolCtx)); - nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; + if(nfcv_data->sub_type == NfcVTypeSniff) { + nfcv_data->emu_protocol_handler = &nfcv_emu_sniff_packet; + } else { + nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; + } } FURI_LOG_D(TAG, "Starting NfcV emulation"); @@ -801,6 +959,9 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { case NfcVTypePlain: FURI_LOG_D(TAG, " Card type: Plain"); break; + case NfcVTypeSniff: + FURI_LOG_D(TAG, " Card type: Sniffing"); + break; } /* allocate a 512 edge buffer, more than enough */ diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index 3f8e78556..fde1c933b 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -96,6 +96,7 @@ typedef enum { NfcVTypeSlixS = 2, NfcVTypeSlixL = 3, NfcVTypeSlix2 = 4, + NfcVTypeSniff = 255, } NfcVSubtype; typedef enum { From 07a44e278ce8d7d2cf036475508ede9d4287ea4c Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 21 Jan 2023 01:13:27 +0100 Subject: [PATCH 053/216] added correct description to delete menu --- applications/main/nfc/scenes/nfc_scene_delete.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index cbb52bfd0..0808db45a 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -31,6 +31,8 @@ void nfc_scene_delete_on_enter(void* context) { nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); NfcProtocol protocol = nfc->dev->dev_data.protocol; + const char* nfc_type = "NFC-A"; + if(protocol == NfcDeviceProtocolEMV) { furi_string_set(temp_str, "EMV bank card"); } else if(protocol == NfcDeviceProtocolMifareUl) { @@ -39,12 +41,15 @@ void nfc_scene_delete_on_enter(void* context) { furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_set(temp_str, "MIFARE DESFire"); + } else if(protocol == NfcDeviceProtocolNfcV) { + furi_string_set(temp_str, "ISO15693 tag"); + nfc_type = "NFC-V"; } else { furi_string_set(temp_str, "Unknown ISO tag"); } widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, nfc_type); furi_string_free(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); From 64badf124acc011777871a2a7b7d0cd4cff6e084 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 21 Jan 2023 01:49:02 +0100 Subject: [PATCH 054/216] also added DSFID/AFI handling and locking --- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 12 +- lib/nfc/nfc_device.c | 7 +- lib/nfc/protocols/nfcv.c | 103 +++++++++++++++++- lib/nfc/protocols/nfcv.h | 7 +- 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 87a23c8ef..38f3e75c7 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -87,8 +87,16 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } furi_string_cat_printf(temp_str, "\n"); - furi_string_cat_printf(temp_str, "DSFID: %02X\n", nfcv_data->dsfid); - furi_string_cat_printf(temp_str, "AFI: %02X\n", nfcv_data->afi); + furi_string_cat_printf( + temp_str, + "DSFID: %02X %s\n", + nfcv_data->dsfid, + (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "AFI: %02X %s\n", + nfcv_data->afi, + (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 0aec74f0f..9646c262e 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -858,8 +858,11 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { if(!flipper_format_write_hex( file, "Data Content", data->data, data->block_num * data->block_size)) break; + if(!flipper_format_write_comment_cstr( + file, "First byte: DSFID (0x01) / AFI (0x02) lock info, others: block lock info")) + break; if(!flipper_format_write_hex( - file, "Security Status", data->security_status, data->block_num)) + file, "Security Status", data->security_status, 1 + data->block_num)) break; if(!flipper_format_write_comment_cstr( file, @@ -916,7 +919,7 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { /* optional, as added later */ if(flipper_format_key_exist(file, "Security Status")) { if(!flipper_format_read_hex( - file, "Security Status", data->security_status, data->block_num)) + file, "Security Status", data->security_status, 1 + data->block_num)) break; } if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break; diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index c9982f156..b2b04f878 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -586,10 +586,73 @@ void nfcv_emu_handle_packet( uint8_t block = nfcv_data->frame[ctx->payload_offset]; nfcv_data->security_status[block] |= 0x01; nfcv_data->modified = true; + + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK BLOCK %d", block); break; } + case ISO15693_WRITE_DSFID: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + + if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) { + nfcv_data->dsfid = id; + nfcv_data->modified = true; + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE DSFID %02X", id); + break; + } + + case ISO15693_WRITE_AFI: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + + if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) { + nfcv_data->afi = id; + nfcv_data->modified = true; + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE AFI %02X", id); + break; + } + + case ISO15693_LOCK_DSFID: { + if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) { + nfcv_data->security_status[0] |= NfcVLockBitDsfid; + nfcv_data->modified = true; + + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK DSFID"); + break; + } + + case ISO15693_LOCK_AFI: { + if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) { + nfcv_data->security_status[0] |= NfcVLockBitAfi; + nfcv_data->modified = true; + + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK AFI"); + break; + } + case ISO15693_SELECT: { ctx->response_buffer[0] = ISO15693_NOERROR; nfcv_data->selected = true; @@ -631,7 +694,8 @@ void nfcv_emu_handle_packet( int block_current = block + block_index; /* prepend security status */ if(ctx->flags & RFAL_NFCV_REQ_FLAG_OPTION) { - ctx->response_buffer[buffer_pos++] = nfcv_data->security_status[block_current]; + ctx->response_buffer[buffer_pos++] = + nfcv_data->security_status[1 + block_current]; } /* then the data block */ memcpy( @@ -794,6 +858,43 @@ void nfcv_emu_sniff_packet( break; } + case ISO15693_WRITE_DSFID: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WR DSFID %d", + flags_string, + id); + break; + } + + case ISO15693_WRITE_AFI: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WR AFI %d", + flags_string, + id); + break; + } + + case ISO15693_LOCK_DSFID: { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s LOCK DSFID", + flags_string); + break; + } + + case ISO15693_LOCK_AFI: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s LOCK AFI", flags_string); + break; + } + case ISO15693_SELECT: { snprintf( nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s SELECT", flags_string); diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index fde1c933b..f1d6e0127 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -85,6 +85,11 @@ extern "C" { #define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful #define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful +typedef enum { + NfcVLockBitDsfid = 1, + NfcVLockBitAfi = 2, +} NfcVLockBits; + typedef enum { NfcVAuthMethodManual, NfcVAuthMethodTonieBox, @@ -174,7 +179,7 @@ typedef struct { uint16_t block_num; uint8_t block_size; uint8_t data[NFCV_MEMSIZE_MAX]; - uint8_t security_status[NFCV_BLOCKS_MAX]; + uint8_t security_status[1 + NFCV_BLOCKS_MAX]; bool selected; bool quiet; From af7d21a02034548b0baa15de41501df80fed1c76 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 21 Jan 2023 01:51:36 +0100 Subject: [PATCH 055/216] increase sniff log size --- applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c | 2 +- lib/nfc/protocols/nfcv.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c b/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c index b2cb58d9f..2c0f17981 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c +++ b/applications/main/nfc/scenes/nfc_scene_nfcv_sniff.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" -#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200) +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (800) enum { NfcSceneNfcVSniffStateWidget, diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index b2b04f878..e18552340 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -836,7 +836,8 @@ void nfcv_emu_sniff_packet( switch(ctx->command) { case ISO15693_INVENTORY: { - snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s INVENTORY", flags_string); break; } From 1d4ce4e78ac4f1339379352d9dd6cd4e318642f8 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 4 Feb 2023 01:43:04 +0100 Subject: [PATCH 056/216] scale NfcV frequency a bit, add echo mode, fix signal level at the end --- lib/nfc/protocols/nfcv.c | 118 ++++++++++++++++++++++++++++++--------- lib/nfc/protocols/nfcv.h | 9 ++- 2 files changed, 100 insertions(+), 27 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index e18552340..e7b6c761a 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -270,16 +270,12 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ return false; } success &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); - for(size_t i = 0; i < slowdown * 24; i++) { + for(size_t i = 0; i < slowdown * 23; i++) { success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); } - for(size_t i = 0; i < slowdown * 3; i++) { - success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); - } - /* add extra silence */ - success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); - if(!success) { - return false; + /* we don't want to add the last level as we just want a transition to "unmodulated" again */ + for(size_t i = 0; i < slowdown; i++) { + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_half_pulse); } } return success; @@ -327,6 +323,18 @@ bool nfcv_emu_alloc(NfcVData* nfcv_data) { nfcv_data->emu_air.nfcv_resp_pulse->edge_cnt = 2; } + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + /* modulated fc/32 or fc/8 pulse as building block */ + nfcv_data->emu_air.nfcv_resp_half_pulse = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + return false; + } + nfcv_data->emu_air.nfcv_resp_half_pulse->start_level = true; + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_cnt = 1; + } + bool success = true; success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); @@ -387,6 +395,9 @@ void nfcv_emu_free(NfcVData* nfcv_data) { if(nfcv_data->emu_air.nfcv_resp_pulse) { digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); } + if(nfcv_data->emu_air.nfcv_resp_half_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_half_pulse); + } if(nfcv_data->emu_air.nfcv_signal) { digital_sequence_free(nfcv_data->emu_air.nfcv_signal); } @@ -397,6 +408,7 @@ void nfcv_emu_free(NfcVData* nfcv_data) { nfcv_data->frame = NULL; nfcv_data->emu_air.nfcv_resp_unmod = NULL; nfcv_data->emu_air.nfcv_resp_pulse = NULL; + nfcv_data->emu_air.nfcv_resp_half_pulse = NULL; nfcv_data->emu_air.nfcv_signal = NULL; nfcv_data->emu_air.reader_signal = NULL; @@ -490,6 +502,18 @@ void nfcv_emu_handle_packet( return; } + if(nfcv_data->echo_mode) { + nfcv_emu_send( + tx_rx, + nfcv_data, + nfcv_data->frame, + nfcv_data->frame_length, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + return; + } + /* parse the frame data for the upcoming part 3 handling */ ctx->flags = nfcv_data->frame[0]; ctx->command = nfcv_data->frame[1]; @@ -500,7 +524,7 @@ void nfcv_emu_handle_packet( ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); ctx->response_flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof; - ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4130); + ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4380); if(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) { ctx->response_flags |= NfcVSendFlagsHighRate; @@ -509,6 +533,11 @@ void nfcv_emu_handle_packet( ctx->response_flags |= NfcVSendFlagsTwoSubcarrier; } + if(ctx->payload_offset + 2 > nfcv_data->frame_length) { + FURI_LOG_D(TAG, "command 0x%02X, but packet is too short", ctx->command); + return; + } + /* standard behavior is implemented */ if(ctx->addressed) { uint8_t* address = &nfcv_data->frame[ctx->address_offset]; @@ -681,11 +710,7 @@ void nfcv_emu_handle_packet( blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; } - if(block + blocks > nfcv_data->block_num) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - nfcv_emu_send( - tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); - } else { + if(block + blocks <= nfcv_data->block_num) { uint8_t buffer_pos = 0; ctx->response_buffer[buffer_pos++] = ISO15693_NOERROR; @@ -719,31 +744,30 @@ void nfcv_emu_handle_packet( case ISO15693_WRITE_MULTI_BLOCK: case ISO15693_WRITEBLOCK: { - uint8_t block = nfcv_data->frame[ctx->payload_offset]; uint8_t blocks = 1; - uint8_t data_pos = 1; + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t data_pos = ctx->payload_offset + 1; if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { - blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + blocks = nfcv_data->frame[data_pos] + 1; data_pos++; } - uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos]; + uint8_t* data = &nfcv_data->frame[data_pos]; uint32_t data_len = nfcv_data->block_size * blocks; - if(block + blocks > nfcv_data->block_num || - ctx->payload_offset + data_len + 2 > nfcv_data->frame_length) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - } else { + if((block + blocks) <= nfcv_data->block_num && + (data_pos + data_len + 2) == nfcv_data->frame_length) { ctx->response_buffer[0] = ISO15693_NOERROR; memcpy( &nfcv_data->data[nfcv_data->block_size * block], - &nfcv_data->frame[ctx->payload_offset + data_pos], + &nfcv_data->frame[data_pos], data_len); nfcv_data->modified = true; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); } - nfcv_emu_send( - tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { snprintf( @@ -782,6 +806,27 @@ void nfcv_emu_handle_packet( break; } + case ISO15693_CUST_ECHO_MODE: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_data->echo_mode = true; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO mode"); + break; + } + + case ISO15693_CUST_ECHO_DATA: { + nfcv_emu_send( + tx_rx, + nfcv_data, + &nfcv_data->frame[ctx->payload_offset], + nfcv_data->frame_length - ctx->payload_offset - 2, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + break; + } + default: snprintf( nfcv_data->last_command, @@ -1112,6 +1157,8 @@ bool nfcv_emu_loop( uint32_t byte_value = 0; uint32_t bits_received = 0; uint32_t timeout = timeout_ms * 1000; + uint32_t sof_timestamp = 0; + uint32_t eof_timestamp = 0; bool wait_for_pulse = false; if(!nfcv_data->ready) { @@ -1153,6 +1200,7 @@ bool nfcv_emu_loop( frame_state = NFCV_FRAME_STATE_SOF2; } else { frame_state = NFCV_FRAME_STATE_SOF1; + sof_timestamp = timestamp; break; } break; @@ -1186,6 +1234,7 @@ bool nfcv_emu_loop( break; } else if(periods == 2) { frame_state = NFCV_FRAME_STATE_EOF; + eof_timestamp = timestamp; break; } @@ -1226,6 +1275,7 @@ bool nfcv_emu_loop( periods_previous = 0; } else if(periods == 2) { frame_state = NFCV_FRAME_STATE_EOF; + eof_timestamp = timestamp; break; } else { frame_state = NFCV_FRAME_STATE_RESET; @@ -1259,6 +1309,24 @@ bool nfcv_emu_loop( tx_rx->sniff_rx(nfcv_data->frame, frame_pos * 8, false, tx_rx->sniff_context); } nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + + + /* determine readers fc by analyzing transmission duration */ + uint32_t duration = eof_timestamp - sof_timestamp; + float fc_1024 = (4.0f * duration) / (4 * (frame_pos * 4 + 1) + 1); + /* it should be 1024/fc in 64MHz ticks */ + float fact = fc_1024 / ((1000000.0f * 64.0f * 1024.0f) / NFCV_FC); + FURI_LOG_D(TAG, "1024/fc: %f -> %f %%", fc_1024, fact * 100); +#if 0 + if(fact > 0.99f && fact < 1.01f) { + static float avg_err = 0.0f; + + avg_err = (avg_err * 15.0f + (fact - 1.0f)) / 16.0f; + FURI_LOG_D(TAG, " ==> set %f %%", (1.0f + avg_err) * 100); + digital_sequence_timebase_correction(nfcv_data->emu_air.nfcv_signal, 1.0f + avg_err); + } +#endif + pulse_reader_start(nfcv_data->emu_air.reader_signal); ret = true; } else { diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index f1d6e0127..56e37f525 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -12,7 +12,7 @@ extern "C" { #endif -#define NFCV_FC (13560000.0f) /* MHz */ +#define NFCV_FC (13560000.0f / 0.9998f) /* MHz */ #define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */ #define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */ @@ -37,7 +37,7 @@ extern "C" { /* helpers to calculate the send time based on DWT->CYCCNT */ #define NFCV_FDT_USEC(usec) (usec * 64) -#define NFCV_FDT_FC(ticks) (ticks * 6400 / 1356) +#define NFCV_FDT_FC(ticks) ((ticks)*6400 / 1356) #define NFCV_FRAME_STATE_SOF1 0 #define NFCV_FRAME_STATE_SOF2 1 @@ -73,6 +73,9 @@ extern "C" { #define ISO15693_GET_SYSTEM_INFO 0x2B #define ISO15693_READ_MULTI_SECSTATUS 0x2C +#define ISO15693_CUST_ECHO_MODE 0xDE +#define ISO15693_CUST_ECHO_DATA 0xDF + /* ISO15693 RESPONSE ERROR CODES */ #define ISO15693_NOERROR 0x00 #define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported @@ -139,6 +142,7 @@ typedef struct { typedef struct { PulseReader* reader_signal; DigitalSignal* nfcv_resp_pulse; /* pulse length, fc/32 */ + DigitalSignal* nfcv_resp_half_pulse; /* half pulse length, fc/32 */ DigitalSignal* nfcv_resp_unmod; /* unmodulated length 256/fc */ NfcVEmuAirSignals signals_high; NfcVEmuAirSignals signals_low; @@ -185,6 +189,7 @@ typedef struct { bool modified; bool ready; + bool echo_mode; /* specfic variant infos */ NfcVSubtype sub_type; From 48e7c67359b254125d4887770cc059b4162a15af Mon Sep 17 00:00:00 2001 From: Tiernan Messmer Date: Mon, 1 May 2023 13:07:33 +1000 Subject: [PATCH 057/216] fix debug print warnings --- lib/nfc/protocols/nfcv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index e7b6c761a..3eb295385 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -1316,13 +1316,13 @@ bool nfcv_emu_loop( float fc_1024 = (4.0f * duration) / (4 * (frame_pos * 4 + 1) + 1); /* it should be 1024/fc in 64MHz ticks */ float fact = fc_1024 / ((1000000.0f * 64.0f * 1024.0f) / NFCV_FC); - FURI_LOG_D(TAG, "1024/fc: %f -> %f %%", fc_1024, fact * 100); + FURI_LOG_D(TAG, "1024/fc: %f -> %f %%", (double)fc_1024, (double)(fact * 100)); #if 0 if(fact > 0.99f && fact < 1.01f) { static float avg_err = 0.0f; avg_err = (avg_err * 15.0f + (fact - 1.0f)) / 16.0f; - FURI_LOG_D(TAG, " ==> set %f %%", (1.0f + avg_err) * 100); + FURI_LOG_D(TAG, " ==> set %f %%", (double)((1.0f + avg_err) * 100)); digital_sequence_timebase_correction(nfcv_data->emu_air.nfcv_signal, 1.0f + avg_err); } #endif From ac9a8c5b90fc842a9a386e2fbe9c132fdd3c955c Mon Sep 17 00:00:00 2001 From: Tiernan Messmer Date: Mon, 1 May 2023 13:07:46 +1000 Subject: [PATCH 058/216] update api_symbols --- firmware/targets/f7/api_symbols.csv | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 3e145d32f..451eb6979 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.1,, +Version,+,23.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2053,12 +2053,25 @@ Function,+,nfc_device_save_shadow,_Bool,"NfcDevice*, const char*" Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,+,nfc_device_set_name,void,"NfcDevice*, const char*" Function,+,nfc_file_select,_Bool,NfcDevice* +Function,-,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" +Function,-,nfc_util_even_parity32,uint8_t,uint32_t +Function,-,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*" +Function,-,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t" +Function,-,nfc_util_odd_parity8,uint8_t,uint8_t Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* +Function,+,nfcv_emu_deinit,void,NfcVData* +Function,+,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*" +Function,+,nfcv_emu_loop,_Bool,"FuriHalNfcTxRxContext*, FuriHalNfcDevData*, NfcVData*, uint32_t" +Function,+,nfcv_emu_send,void,"FuriHalNfcTxRxContext*, NfcVData*, uint8_t*, uint8_t, NfcVSendFlags, uint32_t" +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,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" From a9e47454d5bdf3d08bf77561691e239dacd89660 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 16:17:47 +0300 Subject: [PATCH 059/216] Fix SWD Probe plugin GPIO pins state Reset pins after exit --- applications/external/swd_probe/swd_probe_app.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/applications/external/swd_probe/swd_probe_app.c b/applications/external/swd_probe/swd_probe_app.c index 02cbf8a87..e8846b9e2 100644 --- a/applications/external/swd_probe/swd_probe_app.c +++ b/applications/external/swd_probe/swd_probe_app.c @@ -3166,6 +3166,11 @@ int32_t swd_probe_app_main(void* p) { furi_message_queue_free(app->event_queue); furi_mutex_free(app->gui_mutex); furi_mutex_free(app->swd_mutex); + + // Reset GPIO pins to default state + for(int io = 0; io < 8; io++) { + furi_hal_gpio_init(gpios[io], GpioModeAnalog, GpioPullNo, GpioSpeedLow); + } free(app); furi_record_close(RECORD_GUI); From 3b40696c9efa713c5460800b8d1403502a4a25e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:37:25 +0300 Subject: [PATCH 060/216] Add files via upload --- .../external/flipperzero-bomberduck/LICENSE | 22 + .../external/flipperzero-bomberduck/README.md | 2 + .../flipperzero-bomberduck/application.fam | 15 + .../flipperzero-bomberduck/assets/bomb0.png | Bin 0 -> 4536 bytes .../flipperzero-bomberduck/assets/bomb1.png | Bin 0 -> 4529 bytes .../flipperzero-bomberduck/assets/bomb2.png | Bin 0 -> 4531 bytes .../flipperzero-bomberduck/assets/box.png | Bin 0 -> 4329 bytes .../flipperzero-bomberduck/assets/end.png | Bin 0 -> 4739 bytes .../flipperzero-bomberduck/assets/enemy1.png | Bin 0 -> 4757 bytes .../assets/enemyleft.png | Bin 0 -> 4761 bytes .../assets/enemyright.png | Bin 0 -> 4536 bytes .../flipperzero-bomberduck/assets/explore.png | Bin 0 -> 4540 bytes .../assets/playerleft.png | Bin 0 -> 4311 bytes .../assets/playerright.png | Bin 0 -> 4307 bytes .../assets/unbreakbox.png | Bin 0 -> 4763 bytes .../external/flipperzero-bomberduck/bomb.png | Bin 0 -> 4534 bytes .../flipperzero-bomberduck/bomberduck.c | 645 ++++++++++++++++++ 17 files changed, 684 insertions(+) create mode 100644 applications/external/flipperzero-bomberduck/LICENSE create mode 100644 applications/external/flipperzero-bomberduck/README.md create mode 100644 applications/external/flipperzero-bomberduck/application.fam create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb0.png create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb1.png create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb2.png create mode 100644 applications/external/flipperzero-bomberduck/assets/box.png create mode 100644 applications/external/flipperzero-bomberduck/assets/end.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemy1.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemyleft.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemyright.png create mode 100644 applications/external/flipperzero-bomberduck/assets/explore.png create mode 100644 applications/external/flipperzero-bomberduck/assets/playerleft.png create mode 100644 applications/external/flipperzero-bomberduck/assets/playerright.png create mode 100644 applications/external/flipperzero-bomberduck/assets/unbreakbox.png create mode 100644 applications/external/flipperzero-bomberduck/bomb.png create mode 100644 applications/external/flipperzero-bomberduck/bomberduck.c diff --git a/applications/external/flipperzero-bomberduck/LICENSE b/applications/external/flipperzero-bomberduck/LICENSE new file mode 100644 index 000000000..bce361a99 --- /dev/null +++ b/applications/external/flipperzero-bomberduck/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/applications/external/flipperzero-bomberduck/README.md b/applications/external/flipperzero-bomberduck/README.md new file mode 100644 index 000000000..2d133145a --- /dev/null +++ b/applications/external/flipperzero-bomberduck/README.md @@ -0,0 +1,2 @@ +# flipperzero-bomberduck +Bomberman clone on flipper zero! diff --git a/applications/external/flipperzero-bomberduck/application.fam b/applications/external/flipperzero-bomberduck/application.fam new file mode 100644 index 000000000..afcd5a6ee --- /dev/null +++ b/applications/external/flipperzero-bomberduck/application.fam @@ -0,0 +1,15 @@ +App( + appid="bomberduck", + name="Bomberduck", + apptype=FlipperAppType.EXTERNAL, + entry_point="bomberduck_app", + cdefines=["BOMBERDUCK"], + requires=[ + "gui", + ], + stack_size=1 * 1024, + order=90, + fap_icon="bomb.png", + fap_category="Games", + fap_icon_assets="assets", +) diff --git a/applications/external/flipperzero-bomberduck/assets/bomb0.png b/applications/external/flipperzero-bomberduck/assets/bomb0.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdc3a3c12c7ede770e1c99c2003c777b03f4d75 GIT binary patch literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/bomb1.png b/applications/external/flipperzero-bomberduck/assets/bomb1.png new file mode 100644 index 0000000000000000000000000000000000000000..11d05b9b7c445452253792c5a51ad6448cca8aee GIT binary patch literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/bomb2.png b/applications/external/flipperzero-bomberduck/assets/bomb2.png new file mode 100644 index 0000000000000000000000000000000000000000..38ce7c732bfa5e3586d1c9b9a754b85405cd4566 GIT binary patch literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 zmV1XgTMc#X89QHDSYsLZ;Eip?zDuDazMnbho_o`dKC?ON)Zz6(Vr-zHP8ftfT+~0UY?>&{B)Aq|tz7sb~K6-mW>0A5f zzg)ga`Wu$MC-c$Ot2Uf1ICkwN`u6i(&STi{h11<%>*4a^4JQb*;G_-DjB@{Y~GX07XI+&jiGnm9m+u7+OqYup4iZn!)Gr} zGxskghU;}tTzrz~e7%$8SFf3S;YQ`c6^~p$>iFZ$zcwEGR@cMxKi=Cx@Q0QTRt}!% zs&A`qw0G8@+Wcsd<2&8=>|JrTx#iX$&JMizdviNaTMN>^ao@bi3%?<9e)7PLRTb`D z<;^tGbn@^^_VT9e@^|*P;y>y+c(A2NUNm>@uEqDdvyKOoSNj(=J(T%sUj66qF29rX z8n$oC*ZXEKqyAa^#O(eXd+xSfkN)abN6T|d>XS3DGq;KPv*NXzy3VvVM9x*{hZ}2i ze)kWoul9p&-Q_4M&H5~yoYseW`;$%a@88LE*+9W3Jxe~R9=QF~D{JO`c3J=JlTop2 z_u+Lq;c9kua(cRc*rdHh`>3GJFH&Z8*_m&p|C~*+iQyaY)v^! zamMxQ42}d12_isYkVGULmFa}jsPWRUt(q|-qCu2$r!nC5Audq@h{a?v;b?wBs3MK) z42VPGc)G;BX_NxKIgMqC5~DFJ9*>*iW|Js|FoL2e3@0&?L?Hr|tD_2&K%??Xm12a$ z4P;glVu~O}5tWk(ij|7fXoUU9SbUL~*E>!hl}A;8dSD4Ah7l$li$t)=9jpYw2(-2Erf$p)wqmm@;I6$LkySP$dWn zk(lNM#h!vx1b#xSDY2m)?z1ZRthC? zibX99V?%>x!iMsUg=EZDU}q_662&%2fK|zaCr71Hagd4vI0%~U0HuPA1+@TcE=mCo z@>wV|p9}CH$1)lf$I_cbDZ;?%6e3IrV6kXO>re%!H~KtIBWc1XEWR+K@X*0&+$uyX z6B8YNAp*85jH)JKvy-_LZp$Tb_#nv%P$`gPScxhpft$=0tw)^}8YTmUWz;%_1ezV@ zLc1iuD5B&S#jw+;hJ>h|8PsDNdSc+(MI-pTub^K@)fm4lR@LA}8?G z{|l`y9>g&+<%NO_$FJ5*BP(hIk)h z<*8|fWN8z%W-2;f2Gm)Af}ywtoe+!|6$~3q7*qF*v5Xzqe`(^-0FyQu=r>}6n-|;* zvGL7tR5Nwk`3gUybMY090I6pNnU=mYa?Qv!Ed{0po~f=Gxu&JSw7@gf^?#GgFmas% zQFsc9!^_gAH7PcD(V89HQsCCET)Ka|&V3KI=Ee#imUTMQO7)kNXj)$djdK)_H-FBR zSs9DX^M)S0dBQaH zlF4IiN?T%=QXmAF5>khuB+w?ABtw&-4MQMFO-egsU})OldTbuSv=C^fWD2hPog}}e znaOw>`j<5$>AU@Qf4lqJ-TUsItzKR+EqhKjf*{lUmA)GIZ?3Z^XTsmi>R=!I`}_LZ zpi#re(U_*nN*JIo zICuO{Iol7PyT13C>066Ceo^!0<*Hm=S0)!v+kFJQ5&h9ypWQiex&dv@d#s{w#upO{ z$ck&^#y|e+(8{b&as#&(wPlo)-C*Y|?GNWoeeOf)d%cV4ntPTwZx-f**Dl_8tD*hC znMVR`7m9Q;IJ3C$!JcAi!tJ#=FWt6weJdcg&x&0Nz0$lrd~)gQ2c5yb_Jh;9o_MIJ z{ijcA1x($Qw)syLE@*z|!=GRM^_>3mr+&K+zxiTlzpL~2@rg68xxRrQ89z|G-fF+s zJD503chA#XJ(b577QFxX>7@@9PjAd!*-`z%-?}ID1P@hj%-;WS-PvOoI&<3n-fcZS z3*NrB;7;(D+}rM}eci>AH+&m?)xNydUehzMZE;(E&QEUNxYpHsZ7zD|qbkNiEgf-)oybv+aH7^MBd3W9p7X ztNW#w=Ukk!X6HBm@W`IC+79M=$K&}Y>pxny_5iyn>)zKl<@tX1vS0zhO`Qj~3f92w zbvXmgy(_jZyYJk@eD>1Hmh6rj-yb-3J$mZB3mboy*J_!IAMPhJv*ImFP8~kFC30k4 z<`*xv-2bbKubpYxy`r-o!?di=qn26cut1l^9&i5l{70$pR@^+Dmp!4o|HtnZP5S(N z=J`WW_0-dQN|D)p#Z8uig3Nv8Cm;JqA|85D9oVb<^OmKfUh8=71I<8?oKgjLVlYs} ziE6~oOR50uiAW5#D1wxfC1Si-4-8ZQAtmauUO#fwiYk)Fx|#_PftVN6DV6IruxkDC zT5)~7$V%3-((IB12LU3$;L$`R9M!pm$C||D;Mx@9Ry3(%)O)PKKsD-BHGtA~+D>5Q z38j&;mS&?Rnj~{Iz9nf0c;&Iy8Ago5@pwFLk2~zD7Q#uEWpRSSDGGxcnBEjM_yiW! zZ6-tt!v}OxQ(}gqMo|-!7t{vBW3|G4bTGb1ED#uikLqa_ARl;wkKv@9z#|cSq=jyj zH$sqfKwoO1*TR9uYk;mcXd)|+gDIGK(l;vftnP*sOs$x$vV{DJBr z3zLG75{V_PAlaid4MiR%YgBCJPBNX5fk5*i+)>(txhIvORv^InRI$Mf&+qeCP5+#v zii*S~m$V?bM4q8BmZT|+cDbAwOEYjKxFu0$c$Yx)BcS|I-Qc4lFrgs0U4b}m2kT-b zH;GXqAz?HnIx)B8ggCq?5rmTl0^=9~u|iW|SMuSJQJGMZ2}QC3OR)?lxG4goS%|_* zZXN@Gkttc^ouZtAl02yC1tpg9LoOVS)cag^(R0!l{ctCAu& zeU-L3JZMR(D7kdkpitkjlR$45f| z-aXRoIw)7Zq!mb6qGT8CzyyJSJtR9|{T#9bbCR-5QiMPO(lr`gS7js4YhY0b@(8(t z?V02XU63qP(P-^>9Wbi^3Bw2)qu5%CrXQvcK92KzoDH%M1;E9G09ck&dFb|Kr_(@OHUGxB< z$DNFc-*LLe=^7IQV^SXPu5r4?#K4%8$Ghumqbqy(r5Hrvvuqr`@*XYn9fhyU_rxmK z=m=uBncs}W{<20WoMiX|<&!RF&6|=r_pgU9RYB2gqdaJM)rk2fg(M&FfrQ2tqYgD6 z@K?7?p9PhQ{JurC`KQG@0|R9ii^XQMZOq7s*{8gbYniyPa^IC761(z0+t6O`Ms^D` W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/enemy1.png b/applications/external/flipperzero-bomberduck/assets/enemy1.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee7cb27f1ee52c63dbdb31e788c1011c8448d35 GIT binary patch literal 4757 zcmeHKeQ*?K8DDZ~L(Y;gZ3+PcEO&er*xQfW``9&?K<|#^AV-dH&@fWl{dhOoCU<-6 zZE_bZ*aSL45F@leGo)0-Rw9ayb$|>CLJb-!%7ii~TFfL=FfhR&18RWy?p;2$Gfu|h zU%8pvefNEz=l4F(@A)pRO1up-nWJ}%r-V}HSO=6USEIgpYbb4+b>@E zS<&G)*B_sLVe2bc#;Npmt+~hCH!7Z;_4=Kh8{Veg#)TK=ocQt6flKc#ckO-Um*FLA zmKR=I+AO`icGi~pug;ybq^02C&13Atrt_|Y`M2_ayL{H=y4d8ddv~`W$b{Erw>#i- zy9YCe`8I9ZRa@ZgTODbgrH2Dsjqk24zjXRqd*-)%?%kc8 z3yx38c~JU&_PFzAcgMnsb+gbTmX-CElFt6!&+o|2{CZz+&(*G;8R$nJ7TFBsl1q!t zZ*SZ2`#;uazv@LkxN&Ck*|}2p`^~|p4|Ls}nRoK4w`TACmi&T--HvG;&ukZp9E&@v zI{)Hdas8*oInrF;?7aCitvBj^(Xf8si<`UFYo#5HocWCd=8R`{wA%On;jKMS?TObr zzkO)>C!brl@7dpcvFVb!$9B8zrR;MRAFf#cU1nSAlpk%&^8D%$Zvds++P}ApH~ITE zWcI(-RlIA(yvt8!Gk;!HYi#S?(trAP`23k`TlZ(x8)o1~ACf7lvD#(lkDh7>o!F4_ z_jhU+{os=yepK67++KlUYU+1KOo<`Z)mGf+ul5@Y6y~S!U+{XLwQgphh3)ICr+7AS#+6Ru=xpp#0|>j!i_3ey>Vqw z*jOPjqA5Smm>XvyKnQ3Y8V^;5qioz|O5n1vt#{)lG-0AuxJ;$~0P0p$fYKJ)LSWvw zTuqtsjA*VZN^FT|*#HE5a+%6CEyCh>EEcoGtQJKr!%2o=aDu`q3WF9{v?i=^aV#7) z>kvr{4~Pn?9MNPYjOv&iuT*I+lL?NagYktTe*X}BI6A-rJP zdFT|B$)QNX3z9v`Qj?`&vPQ+Gk0jC=83=SA!X0Hjn0vw)TKWB~M-i&@@O&PZNuQq; z6+sr+M3d%uhrrorj3H?Xqa6-A#?Us{;+>)(**FJJb0eU9;i$%i1)xJgaElCa7~V=z zq}7f&MTy5~jDDTlZ+fJee*i2_LlNl79pf~NrK7>yoPBrV3N zU}+iT5po6PncxatkSNr1qpf4*K(7KM3?pcaVuBROLh>kbfH3^=r)VVzhNgG{qe&59 zw37pv(+&Ve0-mu`a4C@vVRX>{ONvkv1j*WLEJ^(TQY0KApeY9|n;p;?P16j<(T43{CTZ`b<;QWp8JRf2(3HuD|&Qb(@R-hq99fBen`y{bV29g5ZvZ4{d1!vd}k= z$M_pqQIBy32t7W@nD`y1Yn-kzF)$|MadnN;H6{keWIV2}&x|hP@Szxl;kRrI9(m91 z+!Ju^G3);c@ptp9VP~4=^Lx{-r_MCanUH>X^<>yJP4kv&ZY89jq>#i1 zJ`mBEtd*ns2mTAS8B?JV>+>uPW?vK@^!Mi*3`zp7Upp$8Is*uW+&NA zL`zbs0ctr=!Fn1&i)p1&>CqOo0Vx97=)qb7$0un_px98QP>LKC(mS(BNUZ1dY(=+GA znVDZy?BQN?p6lz*o76lTeHJg>h?n>DZ(X=4efp0-zwk*{?hH)X*X{=YTy3;Pq$6kme}b0 z`O_I^zFGO`EpL9e^`y4VcD`d}`s+1sELrhOSIhXBziCPH{_$xc6;!kw|J4@38u)z8 z^!|0dWm}fq@%Dst*I$=5SvoHKp#RYM$gx*WKlrn>jj6X0`>s+cj_o_RIo!S` z<;u>cJAZv)-olB3^Z$+P_1&{Ap@Ojn?tVtD24=(+d=+#EL)( zC#qqbmsA1ZiEtE36hZO}6H#8Q0XiyxDkb8!o^L;BMHR_yy~h?H15ppCR*D-nu&l8( zBsSKFF3DP0V98H#5FiY69!-R6BQY-Fwwkyc92;iBikdEZjoVrg2%;WU11O8LIEncZ zNLJKLLSGpX3&Dma%0W!6(?sB_2N6AcID{k)#YgM3TC*HUBtR_)L)REwl^U^Rkv|X| ziZCdsQo>O)3X(m-Q&;5cWR1wpm@&&4o(K#d!X4o~Si9*Ay#fKwtBQ3-dVa6lYOK#m zs;EeuIb;RFA@VjBb5Sgfu?~kFbFnr!5}cAK+jxh-^24C~k(ka$L|{Nca9n{nA`G&V z62K@%qA*q_X-u&53`UbK$tg>eNQ$;$5M`PIRms;5&&q(3Ae57G2`<`Y!vrTyVyw$< z$9T!fV*uD>S{8Y`C^IIMByx*XEzHC1RKk1}Afk~fbHX5;TM+cStu#(vw*+f>U4{W} zYl#x6OI)7_DPgco=M6R~yOVa>NRp;)b{FML=4|5K4YU|kqJc?~IK!IZ#l&rjwU&pzLSKO zVg9P5$PNF^+h`s%Ke^?_N(`>wV49L0wG6CDUL`MU6|;+E1trfq zd4M_X0E!<7E;|idiE@Y|lm0p-LQRkqXR~n>`Tr}?Ns9tWIc3l&uKd_7WgmLE|)NMZTAIeTT40}|--A~%!BM3gxh@nT?fGl9X zH}W&kQ8#i46dhY+RQ!(7HAdH{7#NlFn7YR38WjVhavoFH|BNon^+Pd;z<1d=Jo28> z+uPxBd2+P4GKL^{w(%X8Xe+FT#)-N=;G1}Me3m6`=3NEdw?oq`-B+P|)Ua`qLd+L@ zAfa(ZuSSg*{Ck?F-3pxw{oVzk^v;I^)C>fjl+xc{m669NElsJuryxeLkp0ky?W+$H z<$LPBbHK8C--2@XFP+ye&RBVdIlcCpy8(G;UQuW0oz(9`D8%n8^*+0BRr9|AWQvH3 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/enemyright.png b/applications/external/flipperzero-bomberduck/assets/enemyright.png new file mode 100644 index 0000000000000000000000000000000000000000..45e6a861ad9c914af25be2b6c1b6097fdc6f0d17 GIT binary patch literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/explore.png b/applications/external/flipperzero-bomberduck/assets/explore.png new file mode 100644 index 0000000000000000000000000000000000000000..5eb50b669b3ee364bd25a37991519cf833660ae5 GIT binary patch literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/playerleft.png b/applications/external/flipperzero-bomberduck/assets/playerleft.png new file mode 100644 index 0000000000000000000000000000000000000000..86997a985eab4de991e315858b17ed7e0a981f74 GIT binary patch literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/playerright.png b/applications/external/flipperzero-bomberduck/assets/playerright.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6283d9c26d9f9582fecd0cef9765ab2b288576 GIT binary patch literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/unbreakbox.png b/applications/external/flipperzero-bomberduck/assets/unbreakbox.png new file mode 100644 index 0000000000000000000000000000000000000000..5e65912d53405d04bcd05916947a8de8fc5239c8 GIT binary patch literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/bomb.png b/applications/external/flipperzero-bomberduck/bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..44b9bfdeae76553be52ce1c451133a4baee7bf68 GIT binary patch literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/bomberduck.c b/applications/external/flipperzero-bomberduck/bomberduck.c new file mode 100644 index 000000000..7b8b5f14a --- /dev/null +++ b/applications/external/flipperzero-bomberduck/bomberduck.c @@ -0,0 +1,645 @@ +#include +#include + +#include +#include +#include +#include +#include +#include "bomberduck_icons.h" +#include + +int max(int a, int b) { + return (a > b) ? a : b; +} + +int min(int a, int b) { + return (a < b) ? a : b; +} + +#define WorldSizeX 12 +#define WorldSizeY 6 +#define BombRange 1 + + +typedef struct { + FuriMutex* mutex; +} BomberState; + +typedef struct { + int row; + int col; +} Cell; + +typedef struct { + Cell cells[WorldSizeY * WorldSizeX]; + int front; + int rear; +} Queue; + +void enqueue(Queue* q, Cell c) { + q->cells[q->rear] = c; + q->rear++; +} + +Cell dequeue(Queue* q) { + Cell c = q->cells[q->front]; + q->front++; + + return c; +} + +bool is_empty(Queue* q) { + return q->front == q->rear; +} + +typedef struct { + int x; + int y; + int planted; +} Bomb; + +typedef struct { + int x; + int y; + bool side; +} Player; + +typedef struct { + int x; + int y; + int last; + bool side; + int level; +} Enemy; + +typedef struct { + int matrix[WorldSizeY][WorldSizeX]; + Player* player; + bool running; + int level; + + Enemy enemies[10]; + int enemies_count; + + Bomb bombs[100]; + int bombs_count; + + int endx; + int endy; +} World; + +Player player = {0, 0, 1}; +World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; +bool vibration = false; + +void init() { + player.x = 1; + player.y = 1; + + world.endx = 4 + rand() % 8; + world.endy = rand() % 6; + for(int i = 0; i < WorldSizeY; i++) { + for(int j = 0; j < WorldSizeX; j++) { + world.matrix[i][j] = rand() % 3; + } + } + world.running = 1; + world.bombs_count =0; + vibration = false; + for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { + world.matrix[j][player.x] = 0; + } + + for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { + world.matrix[player.y][j] = 0; + } + + world.enemies_count = 0; + for(int j = 0; j < rand() % 4 + world.level / 5; j++) { + Enemy enemy; + enemy.x = 4 + rand() % 7; + enemy.y = rand() % 6; + enemy.last = 0; + enemy.side = 1; + enemy.level = 0; + + world.enemies[j] = enemy; + world.enemies_count++; + + for(int m = max(0, world.enemies[j].y - BombRange); + m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); + m++) { + world.matrix[m][world.enemies[j].x] = 0; + } + + for(int m = max(0, world.enemies[j].x - BombRange); + m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); + m++) { + world.matrix[world.enemies[j].y][m] = 0; + } + } + world.matrix[world.endy][world.endx] = 1; +} + +const NotificationSequence end = { + &message_vibro_on, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb2 = { + &message_vibro_on, + &message_delay_25, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb_explore = { + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence vibr1 = { + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + + NULL, +}; + + +void intToStr(int num, char* str) { + int i = 0, sign = 0; + + if(num < 0) { + num = -num; + sign = 1; + } + + do { + str[i++] = num % 10 + '0'; + num /= 10; + } while(num > 0); + + if(sign) { + str[i++] = '-'; + } + + str[i] = '\0'; + + // Reverse the string + int j, len = i; + char temp; + for(j = 0; j < len / 2; j++) { + temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} + +bool BFS() { + // Initialize visited array and queue + int visited[WorldSizeY][WorldSizeX] = {0}; + Queue q = {.front = 0, .rear = 0}; + // Mark the starting cell as visited and enqueue it + visited[world.player->y][world.player->x] = 1; + Cell startCell = {.row = world.player->y, .col = world.player->x}; + enqueue(&q, startCell); + // Traverse the field + while(!is_empty(&q)) { + // Dequeue a cell from the queue + Cell currentCell = dequeue(&q); + // Check if the current cell is the destination cell + if(currentCell.row == world.endy && currentCell.col == world.endx) { + return true; + } + // Check the neighboring cells + for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { + for(int colOffset = -1; colOffset <= 1; colOffset++) { + // Skip diagonals and the current cell + if(rowOffset == 0 && colOffset == 0) { + continue; + } + if(rowOffset != 0 && colOffset != 0) { + continue; + } + // Calculate the row and column of the neighboring cell + int neighborRow = currentCell.row + rowOffset; + int neighborCol = currentCell.col + colOffset; + // Skip out-of-bounds cells and already visited cells + if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || + neighborCol >= WorldSizeX) { + continue; + } + if(visited[neighborRow][neighborCol]) { + continue; + } + // Mark the neighboring cell as visited and enqueue it + if(world.matrix[neighborRow][neighborCol] != 2) { + visited[neighborRow][neighborCol] = 1; + Cell neighborCell = {.row = neighborRow, .col = neighborCol}; + enqueue(&q, neighborCell); + } + } + } + } + return false; +} + +static void draw_callback(Canvas* canvas, void* ctx) { + furi_assert(ctx); + const BomberState* bomber_state = ctx; + + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + if(!BFS()) { + init(); + } + canvas_clear(canvas); + + canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); + + if(world.running) { + for(size_t i = 0; i < WorldSizeY; i++) { + for(size_t j = 0; j < WorldSizeX; j++) { + switch(world.matrix[i][j]) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); + break; + case 2: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); + break; + case 3: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); + break; + case 4: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); + break; + case 5: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); + break; + case 6: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); + world.matrix[i][j] = 0; + break; + } + } + } + + if(world.player->side) { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); + } else { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); + } + + for(int i = 0; i < world.enemies_count; i++) { + if(world.enemies[i].level > 0) { + canvas_draw_icon( + canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); + } else { + if(world.enemies[i].side) { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyright); + } else { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyleft); + } + } + } + } else { + canvas_set_font(canvas, FontPrimary); + if(world.player->x == world.endx && world.player->y == world.endy) { + if(world.level == 20) { + canvas_draw_str(canvas, 30, 35, "You win!"); + }else{ + canvas_draw_str(canvas, 30, 35, "Next level!"); + char str[20]; + intToStr(world.level, str); + canvas_draw_str(canvas, 90, 35, str); + } + + } else { + canvas_draw_str(canvas, 30, 35, "You died :("); + } + } + + furi_mutex_release(bomber_state->mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + // Проверяем, что контекст не нулевой + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + + furi_message_queue_put(event_queue, input_event, FuriWaitForever); +} + +int32_t bomberduck_app(void* p) { + UNUSED(p); + + // Текущее событие типа InputEvent + InputEvent event; + // Очередь событий на 8 элементов размера InputEvent + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + BomberState* bomber_state = malloc(sizeof(BomberState)); + + bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex + if(!bomber_state->mutex) { + FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + free(bomber_state); + return 255; + } + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + // Создаем новый view port + ViewPort* view_port = view_port_alloc(); + // Создаем callback отрисовки, без контекста + view_port_draw_callback_set(view_port, draw_callback, bomber_state); + // Создаем callback нажатий на клавиши, в качестве контекста передаем + // нашу очередь сообщений, чтоб запихивать в неё эти события + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Создаем GUI приложения + Gui* gui = furi_record_open(RECORD_GUI); + // Подключаем view port к GUI в полноэкранном режиме + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message_block(notification, &sequence_display_backlight_enforce_on); + + init(); + + // Бесконечный цикл обработки очереди событий + while(1) { + if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения + + if(event.type == InputTypePress) { + if(event.key == InputKeyOk) { + if(world.running) { + if(world.matrix[world.player->y][world.player->x] == 0 && + world.bombs_count < 2) { + notification_message(notification, &bomb2); + world.matrix[world.player->y][world.player->x] = 3; + Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; + world.bombs[world.bombs_count] = bomb; + world.bombs_count++; + } + } else { + init(); + } + } + if(world.running) { + if(event.key == InputKeyUp) { + if(world.player->y > 0 && + world.matrix[world.player->y - 1][world.player->x] == 0) + world.player->y--; + } + if(event.key == InputKeyDown) { + if(world.player->y < WorldSizeY - 1 && + world.matrix[world.player->y + 1][world.player->x] == 0) + world.player->y++; + } + if(event.key == InputKeyLeft) { + world.player->side = 0; + if(world.player->x > 0 && + world.matrix[world.player->y][world.player->x - 1] == 0) + world.player->x--; + } + if(event.key == InputKeyRight) { + world.player->side = 1; + if(world.player->x < WorldSizeX - 1 && + world.matrix[world.player->y][world.player->x + 1] == 0) + world.player->x++; + } + } + } else if(event.type == InputTypeLong) { + if(event.key == InputKeyBack) { + break; + } + } + } + if(world.running) { + if(world.player->x == world.endx && world.player->y == world.endy) { + notification_message(notification, &end); + world.running = 0; + world.level += 1; + if(world.level%5==0){ + DOLPHIN_DEED(DolphinDeedPluginGameWin); + } + } + for(int i = 0; i < world.bombs_count; i++) { + if(furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150), 1000)) { + vibration = false; + world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; + notification_message(notification, &bomb_explore); + + for(int j = max(0, world.bombs[i].y - BombRange); + j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); + j++) { + if(world.matrix[j][world.bombs[i].x] != 2) { + world.matrix[j][world.bombs[i].x] = 6; + if(j == world.player->y && world.bombs[i].x == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(j == world.enemies[e].y && + world.bombs[i].x == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = max(0, world.bombs[i].x - BombRange); + j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); + j++) { + if(world.matrix[world.bombs[i].y][j] != 2) { + world.matrix[world.bombs[i].y][j] = 6; + if(world.bombs[i].y == world.player->y && j == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.bombs[i].y == world.enemies[e].y && + j == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = i; j < world.bombs_count - 1; j++) { + world.bombs[j] = world.bombs[j + 1]; + } + world.bombs_count--; + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration=true; + + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; + + } + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.player->y == world.enemies[e].y && + world.player->x == world.enemies[e].x) { + notification_message(notification, &end); + world.running = 0; + } + } + + for(int e = 0; e < world.enemies_count; e++) { + if(world.enemies[e].level > 0) { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((2000 - world.level * 100), 1000)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) + world.enemies[e].x++; + default: + break; + } + } + } else { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((1000 - world.level * 50), 500)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) + world.enemies[e].x++; + default: + break; + } + } + } + } + for(int e = 0; e < world.enemies_count; e++) { + for(int h = e + 1; h < world.enemies_count; h++) { + if(world.enemies[e].y == world.enemies[h].y && + world.enemies[e].x == world.enemies[h].x) { + world.enemies[h].level++; + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + if(vibration){ + notification_message(notification, &vibr1); + } + } + + view_port_update(view_port); + furi_mutex_release(bomber_state->mutex); + } + + // Return to normal backlight settings + notification_message_block(notification, &sequence_display_backlight_enforce_auto); + furi_record_close(RECORD_NOTIFICATION); + // Специальная очистка памяти, занимаемой очередью + furi_message_queue_free(event_queue); + + // Чистим созданные объекты, связанные с интерфейсом + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + + furi_mutex_free(bomber_state->mutex); + furi_record_close(RECORD_GUI); + free(bomber_state); + + return 0; +} From b65f6665785feb802852560894b28bf20f68ae93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:38:57 +0300 Subject: [PATCH 061/216] Delete applications/external/flipperzero-bomberduck directory --- .../external/flipperzero-bomberduck/LICENSE | 22 - .../external/flipperzero-bomberduck/README.md | 2 - .../flipperzero-bomberduck/application.fam | 15 - .../flipperzero-bomberduck/assets/bomb0.png | Bin 4536 -> 0 bytes .../flipperzero-bomberduck/assets/bomb1.png | Bin 4529 -> 0 bytes .../flipperzero-bomberduck/assets/bomb2.png | Bin 4531 -> 0 bytes .../flipperzero-bomberduck/assets/box.png | Bin 4329 -> 0 bytes .../flipperzero-bomberduck/assets/end.png | Bin 4739 -> 0 bytes .../flipperzero-bomberduck/assets/enemy1.png | Bin 4757 -> 0 bytes .../assets/enemyleft.png | Bin 4761 -> 0 bytes .../assets/enemyright.png | Bin 4536 -> 0 bytes .../flipperzero-bomberduck/assets/explore.png | Bin 4540 -> 0 bytes .../assets/playerleft.png | Bin 4311 -> 0 bytes .../assets/playerright.png | Bin 4307 -> 0 bytes .../assets/unbreakbox.png | Bin 4763 -> 0 bytes .../external/flipperzero-bomberduck/bomb.png | Bin 4534 -> 0 bytes .../flipperzero-bomberduck/bomberduck.c | 645 ------------------ 17 files changed, 684 deletions(-) delete mode 100644 applications/external/flipperzero-bomberduck/LICENSE delete mode 100644 applications/external/flipperzero-bomberduck/README.md delete mode 100644 applications/external/flipperzero-bomberduck/application.fam delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb0.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb1.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb2.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/box.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/end.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemy1.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemyleft.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemyright.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/explore.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/playerleft.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/playerright.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/unbreakbox.png delete mode 100644 applications/external/flipperzero-bomberduck/bomb.png delete mode 100644 applications/external/flipperzero-bomberduck/bomberduck.c diff --git a/applications/external/flipperzero-bomberduck/LICENSE b/applications/external/flipperzero-bomberduck/LICENSE deleted file mode 100644 index bce361a99..000000000 --- a/applications/external/flipperzero-bomberduck/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) [year] [fullname] - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/applications/external/flipperzero-bomberduck/README.md b/applications/external/flipperzero-bomberduck/README.md deleted file mode 100644 index 2d133145a..000000000 --- a/applications/external/flipperzero-bomberduck/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# flipperzero-bomberduck -Bomberman clone on flipper zero! diff --git a/applications/external/flipperzero-bomberduck/application.fam b/applications/external/flipperzero-bomberduck/application.fam deleted file mode 100644 index afcd5a6ee..000000000 --- a/applications/external/flipperzero-bomberduck/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="bomberduck", - name="Bomberduck", - apptype=FlipperAppType.EXTERNAL, - entry_point="bomberduck_app", - cdefines=["BOMBERDUCK"], - requires=[ - "gui", - ], - stack_size=1 * 1024, - order=90, - fap_icon="bomb.png", - fap_category="Games", - fap_icon_assets="assets", -) diff --git a/applications/external/flipperzero-bomberduck/assets/bomb0.png b/applications/external/flipperzero-bomberduck/assets/bomb0.png deleted file mode 100644 index 3fdc3a3c12c7ede770e1c99c2003c777b03f4d75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U diff --git a/applications/external/flipperzero-bomberduck/assets/bomb1.png b/applications/external/flipperzero-bomberduck/assets/bomb1.png deleted file mode 100644 index 11d05b9b7c445452253792c5a51ad6448cca8aee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& diff --git a/applications/external/flipperzero-bomberduck/assets/bomb2.png b/applications/external/flipperzero-bomberduck/assets/bomb2.png deleted file mode 100644 index 38ce7c732bfa5e3586d1c9b9a754b85405cd4566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 zmV1XgTMc#X89QHDSYsLZ;Eip?zDuDazMnbho_o`dKC?ON)Zz6(Vr-zHP8ftfT+~0UY?>&{B)Aq|tz7sb~K6-mW>0A5f zzg)ga`Wu$MC-c$Ot2Uf1ICkwN`u6i(&STi{h11<%>*4a^4JQb*;G_-DjB@{Y~GX07XI+&jiGnm9m+u7+OqYup4iZn!)Gr} zGxskghU;}tTzrz~e7%$8SFf3S;YQ`c6^~p$>iFZ$zcwEGR@cMxKi=Cx@Q0QTRt}!% zs&A`qw0G8@+Wcsd<2&8=>|JrTx#iX$&JMizdviNaTMN>^ao@bi3%?<9e)7PLRTb`D z<;^tGbn@^^_VT9e@^|*P;y>y+c(A2NUNm>@uEqDdvyKOoSNj(=J(T%sUj66qF29rX z8n$oC*ZXEKqyAa^#O(eXd+xSfkN)abN6T|d>XS3DGq;KPv*NXzy3VvVM9x*{hZ}2i ze)kWoul9p&-Q_4M&H5~yoYseW`;$%a@88LE*+9W3Jxe~R9=QF~D{JO`c3J=JlTop2 z_u+Lq;c9kua(cRc*rdHh`>3GJFH&Z8*_m&p|C~*+iQyaY)v^! zamMxQ42}d12_isYkVGULmFa}jsPWRUt(q|-qCu2$r!nC5Audq@h{a?v;b?wBs3MK) z42VPGc)G;BX_NxKIgMqC5~DFJ9*>*iW|Js|FoL2e3@0&?L?Hr|tD_2&K%??Xm12a$ z4P;glVu~O}5tWk(ij|7fXoUU9SbUL~*E>!hl}A;8dSD4Ah7l$li$t)=9jpYw2(-2Erf$p)wqmm@;I6$LkySP$dWn zk(lNM#h!vx1b#xSDY2m)?z1ZRthC? zibX99V?%>x!iMsUg=EZDU}q_662&%2fK|zaCr71Hagd4vI0%~U0HuPA1+@TcE=mCo z@>wV|p9}CH$1)lf$I_cbDZ;?%6e3IrV6kXO>re%!H~KtIBWc1XEWR+K@X*0&+$uyX z6B8YNAp*85jH)JKvy-_LZp$Tb_#nv%P$`gPScxhpft$=0tw)^}8YTmUWz;%_1ezV@ zLc1iuD5B&S#jw+;hJ>h|8PsDNdSc+(MI-pTub^K@)fm4lR@LA}8?G z{|l`y9>g&+<%NO_$FJ5*BP(hIk)h z<*8|fWN8z%W-2;f2Gm)Af}ywtoe+!|6$~3q7*qF*v5Xzqe`(^-0FyQu=r>}6n-|;* zvGL7tR5Nwk`3gUybMY090I6pNnU=mYa?Qv!Ed{0po~f=Gxu&JSw7@gf^?#GgFmas% zQFsc9!^_gAH7PcD(V89HQsCCET)Ka|&V3KI=Ee#imUTMQO7)kNXj)$djdK)_H-FBR zSs9DX^M)S0dBQaH zlF4IiN?T%=QXmAF5>khuB+w?ABtw&-4MQMFO-egsU})OldTbuSv=C^fWD2hPog}}e znaOw>`j<5$>AU@Qf4lqJ-TUsItzKR+EqhKjf*{lUmA)GIZ?3Z^XTsmi>R=!I`}_LZ zpi#re(U_*nN*JIo zICuO{Iol7PyT13C>066Ceo^!0<*Hm=S0)!v+kFJQ5&h9ypWQiex&dv@d#s{w#upO{ z$ck&^#y|e+(8{b&as#&(wPlo)-C*Y|?GNWoeeOf)d%cV4ntPTwZx-f**Dl_8tD*hC znMVR`7m9Q;IJ3C$!JcAi!tJ#=FWt6weJdcg&x&0Nz0$lrd~)gQ2c5yb_Jh;9o_MIJ z{ijcA1x($Qw)syLE@*z|!=GRM^_>3mr+&K+zxiTlzpL~2@rg68xxRrQ89z|G-fF+s zJD503chA#XJ(b577QFxX>7@@9PjAd!*-`z%-?}ID1P@hj%-;WS-PvOoI&<3n-fcZS z3*NrB;7;(D+}rM}eci>AH+&m?)xNydUehzMZE;(E&QEUNxYpHsZ7zD|qbkNiEgf-)oybv+aH7^MBd3W9p7X ztNW#w=Ukk!X6HBm@W`IC+79M=$K&}Y>pxny_5iyn>)zKl<@tX1vS0zhO`Qj~3f92w zbvXmgy(_jZyYJk@eD>1Hmh6rj-yb-3J$mZB3mboy*J_!IAMPhJv*ImFP8~kFC30k4 z<`*xv-2bbKubpYxy`r-o!?di=qn26cut1l^9&i5l{70$pR@^+Dmp!4o|HtnZP5S(N z=J`WW_0-dQN|D)p#Z8uig3Nv8Cm;JqA|85D9oVb<^OmKfUh8=71I<8?oKgjLVlYs} ziE6~oOR50uiAW5#D1wxfC1Si-4-8ZQAtmauUO#fwiYk)Fx|#_PftVN6DV6IruxkDC zT5)~7$V%3-((IB12LU3$;L$`R9M!pm$C||D;Mx@9Ry3(%)O)PKKsD-BHGtA~+D>5Q z38j&;mS&?Rnj~{Iz9nf0c;&Iy8Ago5@pwFLk2~zD7Q#uEWpRSSDGGxcnBEjM_yiW! zZ6-tt!v}OxQ(}gqMo|-!7t{vBW3|G4bTGb1ED#uikLqa_ARl;wkKv@9z#|cSq=jyj zH$sqfKwoO1*TR9uYk;mcXd)|+gDIGK(l;vftnP*sOs$x$vV{DJBr z3zLG75{V_PAlaid4MiR%YgBCJPBNX5fk5*i+)>(txhIvORv^InRI$Mf&+qeCP5+#v zii*S~m$V?bM4q8BmZT|+cDbAwOEYjKxFu0$c$Yx)BcS|I-Qc4lFrgs0U4b}m2kT-b zH;GXqAz?HnIx)B8ggCq?5rmTl0^=9~u|iW|SMuSJQJGMZ2}QC3OR)?lxG4goS%|_* zZXN@Gkttc^ouZtAl02yC1tpg9LoOVS)cag^(R0!l{ctCAu& zeU-L3JZMR(D7kdkpitkjlR$45f| z-aXRoIw)7Zq!mb6qGT8CzyyJSJtR9|{T#9bbCR-5QiMPO(lr`gS7js4YhY0b@(8(t z?V02XU63qP(P-^>9Wbi^3Bw2)qu5%CrXQvcK92KzoDH%M1;E9G09ck&dFb|Kr_(@OHUGxB< z$DNFc-*LLe=^7IQV^SXPu5r4?#K4%8$Ghumqbqy(r5Hrvvuqr`@*XYn9fhyU_rxmK z=m=uBncs}W{<20WoMiX|<&!RF&6|=r_pgU9RYB2gqdaJM)rk2fg(M&FfrQ2tqYgD6 z@K?7?p9PhQ{JurC`KQG@0|R9ii^XQMZOq7s*{8gbYniyPa^IC761(z0+t6O`Ms^D` W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX diff --git a/applications/external/flipperzero-bomberduck/assets/enemy1.png b/applications/external/flipperzero-bomberduck/assets/enemy1.png deleted file mode 100644 index 7ee7cb27f1ee52c63dbdb31e788c1011c8448d35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4757 zcmeHKeQ*?K8DDZ~L(Y;gZ3+PcEO&er*xQfW``9&?K<|#^AV-dH&@fWl{dhOoCU<-6 zZE_bZ*aSL45F@leGo)0-Rw9ayb$|>CLJb-!%7ii~TFfL=FfhR&18RWy?p;2$Gfu|h zU%8pvefNEz=l4F(@A)pRO1up-nWJ}%r-V}HSO=6USEIgpYbb4+b>@E zS<&G)*B_sLVe2bc#;Npmt+~hCH!7Z;_4=Kh8{Veg#)TK=ocQt6flKc#ckO-Um*FLA zmKR=I+AO`icGi~pug;ybq^02C&13Atrt_|Y`M2_ayL{H=y4d8ddv~`W$b{Erw>#i- zy9YCe`8I9ZRa@ZgTODbgrH2Dsjqk24zjXRqd*-)%?%kc8 z3yx38c~JU&_PFzAcgMnsb+gbTmX-CElFt6!&+o|2{CZz+&(*G;8R$nJ7TFBsl1q!t zZ*SZ2`#;uazv@LkxN&Ck*|}2p`^~|p4|Ls}nRoK4w`TACmi&T--HvG;&ukZp9E&@v zI{)Hdas8*oInrF;?7aCitvBj^(Xf8si<`UFYo#5HocWCd=8R`{wA%On;jKMS?TObr zzkO)>C!brl@7dpcvFVb!$9B8zrR;MRAFf#cU1nSAlpk%&^8D%$Zvds++P}ApH~ITE zWcI(-RlIA(yvt8!Gk;!HYi#S?(trAP`23k`TlZ(x8)o1~ACf7lvD#(lkDh7>o!F4_ z_jhU+{os=yepK67++KlUYU+1KOo<`Z)mGf+ul5@Y6y~S!U+{XLwQgphh3)ICr+7AS#+6Ru=xpp#0|>j!i_3ey>Vqw z*jOPjqA5Smm>XvyKnQ3Y8V^;5qioz|O5n1vt#{)lG-0AuxJ;$~0P0p$fYKJ)LSWvw zTuqtsjA*VZN^FT|*#HE5a+%6CEyCh>EEcoGtQJKr!%2o=aDu`q3WF9{v?i=^aV#7) z>kvr{4~Pn?9MNPYjOv&iuT*I+lL?NagYktTe*X}BI6A-rJP zdFT|B$)QNX3z9v`Qj?`&vPQ+Gk0jC=83=SA!X0Hjn0vw)TKWB~M-i&@@O&PZNuQq; z6+sr+M3d%uhrrorj3H?Xqa6-A#?Us{;+>)(**FJJb0eU9;i$%i1)xJgaElCa7~V=z zq}7f&MTy5~jDDTlZ+fJee*i2_LlNl79pf~NrK7>yoPBrV3N zU}+iT5po6PncxatkSNr1qpf4*K(7KM3?pcaVuBROLh>kbfH3^=r)VVzhNgG{qe&59 zw37pv(+&Ve0-mu`a4C@vVRX>{ONvkv1j*WLEJ^(TQY0KApeY9|n;p;?P16j<(T43{CTZ`b<;QWp8JRf2(3HuD|&Qb(@R-hq99fBen`y{bV29g5ZvZ4{d1!vd}k= z$M_pqQIBy32t7W@nD`y1Yn-kzF)$|MadnN;H6{keWIV2}&x|hP@Szxl;kRrI9(m91 z+!Ju^G3);c@ptp9VP~4=^Lx{-r_MCanUH>X^<>yJP4kv&ZY89jq>#i1 zJ`mBEtd*ns2mTAS8B?JV>+>uPW?vK@^!Mi*3`zp7Upp$8Is*uW+&NA zL`zbs0ctr=!Fn1&i)p1&>CqOo0Vx97=)qb7$0un_px98QP>LKC(mS(BNUZ1dY(=+GA znVDZy?BQN?p6lz*o76lTeHJg>h?n>DZ(X=4efp0-zwk*{?hH)X*X{=YTy3;Pq$6kme}b0 z`O_I^zFGO`EpL9e^`y4VcD`d}`s+1sELrhOSIhXBziCPH{_$xc6;!kw|J4@38u)z8 z^!|0dWm}fq@%Dst*I$=5SvoHKp#RYM$gx*WKlrn>jj6X0`>s+cj_o_RIo!S` z<;u>cJAZv)-olB3^Z$+P_1&{Ap@Ojn?tVtD24=(+d=+#EL)( zC#qqbmsA1ZiEtE36hZO}6H#8Q0XiyxDkb8!o^L;BMHR_yy~h?H15ppCR*D-nu&l8( zBsSKFF3DP0V98H#5FiY69!-R6BQY-Fwwkyc92;iBikdEZjoVrg2%;WU11O8LIEncZ zNLJKLLSGpX3&Dma%0W!6(?sB_2N6AcID{k)#YgM3TC*HUBtR_)L)REwl^U^Rkv|X| ziZCdsQo>O)3X(m-Q&;5cWR1wpm@&&4o(K#d!X4o~Si9*Ay#fKwtBQ3-dVa6lYOK#m zs;EeuIb;RFA@VjBb5Sgfu?~kFbFnr!5}cAK+jxh-^24C~k(ka$L|{Nca9n{nA`G&V z62K@%qA*q_X-u&53`UbK$tg>eNQ$;$5M`PIRms;5&&q(3Ae57G2`<`Y!vrTyVyw$< z$9T!fV*uD>S{8Y`C^IIMByx*XEzHC1RKk1}Afk~fbHX5;TM+cStu#(vw*+f>U4{W} zYl#x6OI)7_DPgco=M6R~yOVa>NRp;)b{FML=4|5K4YU|kqJc?~IK!IZ#l&rjwU&pzLSKO zVg9P5$PNF^+h`s%Ke^?_N(`>wV49L0wG6CDUL`MU6|;+E1trfq zd4M_X0E!<7E;|idiE@Y|lm0p-LQRkqXR~n>`Tr}?Ns9tWIc3l&uKd_7WgmLE|)NMZTAIeTT40}|--A~%!BM3gxh@nT?fGl9X zH}W&kQ8#i46dhY+RQ!(7HAdH{7#NlFn7YR38WjVhavoFH|BNon^+Pd;z<1d=Jo28> z+uPxBd2+P4GKL^{w(%X8Xe+FT#)-N=;G1}Me3m6`=3NEdw?oq`-B+P|)Ua`qLd+L@ zAfa(ZuSSg*{Ck?F-3pxw{oVzk^v;I^)C>fjl+xc{m669NElsJuryxeLkp0ky?W+$H z<$LPBbHK8C--2@XFP+ye&RBVdIlcCpy8(G;UQuW0oz(9`D8%n8^*+0BRr9|AWQvH3 diff --git a/applications/external/flipperzero-bomberduck/assets/enemyright.png b/applications/external/flipperzero-bomberduck/assets/enemyright.png deleted file mode 100644 index 45e6a861ad9c914af25be2b6c1b6097fdc6f0d17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD diff --git a/applications/external/flipperzero-bomberduck/assets/explore.png b/applications/external/flipperzero-bomberduck/assets/explore.png deleted file mode 100644 index 5eb50b669b3ee364bd25a37991519cf833660ae5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 diff --git a/applications/external/flipperzero-bomberduck/assets/playerleft.png b/applications/external/flipperzero-bomberduck/assets/playerleft.png deleted file mode 100644 index 86997a985eab4de991e315858b17ed7e0a981f74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF diff --git a/applications/external/flipperzero-bomberduck/assets/playerright.png b/applications/external/flipperzero-bomberduck/assets/playerright.png deleted file mode 100644 index 1a6283d9c26d9f9582fecd0cef9765ab2b288576..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng diff --git a/applications/external/flipperzero-bomberduck/assets/unbreakbox.png b/applications/external/flipperzero-bomberduck/assets/unbreakbox.png deleted file mode 100644 index 5e65912d53405d04bcd05916947a8de8fc5239c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX diff --git a/applications/external/flipperzero-bomberduck/bomb.png b/applications/external/flipperzero-bomberduck/bomb.png deleted file mode 100644 index 44b9bfdeae76553be52ce1c451133a4baee7bf68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 diff --git a/applications/external/flipperzero-bomberduck/bomberduck.c b/applications/external/flipperzero-bomberduck/bomberduck.c deleted file mode 100644 index 7b8b5f14a..000000000 --- a/applications/external/flipperzero-bomberduck/bomberduck.c +++ /dev/null @@ -1,645 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include "bomberduck_icons.h" -#include - -int max(int a, int b) { - return (a > b) ? a : b; -} - -int min(int a, int b) { - return (a < b) ? a : b; -} - -#define WorldSizeX 12 -#define WorldSizeY 6 -#define BombRange 1 - - -typedef struct { - FuriMutex* mutex; -} BomberState; - -typedef struct { - int row; - int col; -} Cell; - -typedef struct { - Cell cells[WorldSizeY * WorldSizeX]; - int front; - int rear; -} Queue; - -void enqueue(Queue* q, Cell c) { - q->cells[q->rear] = c; - q->rear++; -} - -Cell dequeue(Queue* q) { - Cell c = q->cells[q->front]; - q->front++; - - return c; -} - -bool is_empty(Queue* q) { - return q->front == q->rear; -} - -typedef struct { - int x; - int y; - int planted; -} Bomb; - -typedef struct { - int x; - int y; - bool side; -} Player; - -typedef struct { - int x; - int y; - int last; - bool side; - int level; -} Enemy; - -typedef struct { - int matrix[WorldSizeY][WorldSizeX]; - Player* player; - bool running; - int level; - - Enemy enemies[10]; - int enemies_count; - - Bomb bombs[100]; - int bombs_count; - - int endx; - int endy; -} World; - -Player player = {0, 0, 1}; -World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; -bool vibration = false; - -void init() { - player.x = 1; - player.y = 1; - - world.endx = 4 + rand() % 8; - world.endy = rand() % 6; - for(int i = 0; i < WorldSizeY; i++) { - for(int j = 0; j < WorldSizeX; j++) { - world.matrix[i][j] = rand() % 3; - } - } - world.running = 1; - world.bombs_count =0; - vibration = false; - for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { - world.matrix[j][player.x] = 0; - } - - for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { - world.matrix[player.y][j] = 0; - } - - world.enemies_count = 0; - for(int j = 0; j < rand() % 4 + world.level / 5; j++) { - Enemy enemy; - enemy.x = 4 + rand() % 7; - enemy.y = rand() % 6; - enemy.last = 0; - enemy.side = 1; - enemy.level = 0; - - world.enemies[j] = enemy; - world.enemies_count++; - - for(int m = max(0, world.enemies[j].y - BombRange); - m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); - m++) { - world.matrix[m][world.enemies[j].x] = 0; - } - - for(int m = max(0, world.enemies[j].x - BombRange); - m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); - m++) { - world.matrix[world.enemies[j].y][m] = 0; - } - } - world.matrix[world.endy][world.endx] = 1; -} - -const NotificationSequence end = { - &message_vibro_on, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_vibro_off, - NULL, -}; - -static const NotificationSequence bomb2 = { - &message_vibro_on, - &message_delay_25, - &message_vibro_off, - NULL, -}; - -static const NotificationSequence bomb_explore = { - &message_vibro_on, - &message_delay_50, - &message_vibro_off, - NULL, -}; - -static const NotificationSequence vibr1 = { - &message_vibro_on, - &message_delay_10, - &message_vibro_off, - &message_delay_10, - &message_vibro_on, - &message_delay_10, - &message_vibro_off, - &message_delay_10, - - NULL, -}; - - -void intToStr(int num, char* str) { - int i = 0, sign = 0; - - if(num < 0) { - num = -num; - sign = 1; - } - - do { - str[i++] = num % 10 + '0'; - num /= 10; - } while(num > 0); - - if(sign) { - str[i++] = '-'; - } - - str[i] = '\0'; - - // Reverse the string - int j, len = i; - char temp; - for(j = 0; j < len / 2; j++) { - temp = str[j]; - str[j] = str[len - j - 1]; - str[len - j - 1] = temp; - } -} - -bool BFS() { - // Initialize visited array and queue - int visited[WorldSizeY][WorldSizeX] = {0}; - Queue q = {.front = 0, .rear = 0}; - // Mark the starting cell as visited and enqueue it - visited[world.player->y][world.player->x] = 1; - Cell startCell = {.row = world.player->y, .col = world.player->x}; - enqueue(&q, startCell); - // Traverse the field - while(!is_empty(&q)) { - // Dequeue a cell from the queue - Cell currentCell = dequeue(&q); - // Check if the current cell is the destination cell - if(currentCell.row == world.endy && currentCell.col == world.endx) { - return true; - } - // Check the neighboring cells - for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { - for(int colOffset = -1; colOffset <= 1; colOffset++) { - // Skip diagonals and the current cell - if(rowOffset == 0 && colOffset == 0) { - continue; - } - if(rowOffset != 0 && colOffset != 0) { - continue; - } - // Calculate the row and column of the neighboring cell - int neighborRow = currentCell.row + rowOffset; - int neighborCol = currentCell.col + colOffset; - // Skip out-of-bounds cells and already visited cells - if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || - neighborCol >= WorldSizeX) { - continue; - } - if(visited[neighborRow][neighborCol]) { - continue; - } - // Mark the neighboring cell as visited and enqueue it - if(world.matrix[neighborRow][neighborCol] != 2) { - visited[neighborRow][neighborCol] = 1; - Cell neighborCell = {.row = neighborRow, .col = neighborCol}; - enqueue(&q, neighborCell); - } - } - } - } - return false; -} - -static void draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const BomberState* bomber_state = ctx; - - furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); - if(!BFS()) { - init(); - } - canvas_clear(canvas); - - canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); - - if(world.running) { - for(size_t i = 0; i < WorldSizeY; i++) { - for(size_t j = 0; j < WorldSizeX; j++) { - switch(world.matrix[i][j]) { - case 0: - break; - case 1: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); - break; - case 2: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); - break; - case 3: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); - break; - case 4: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); - break; - case 5: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); - break; - case 6: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); - world.matrix[i][j] = 0; - break; - } - } - } - - if(world.player->side) { - canvas_draw_icon( - canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); - } else { - canvas_draw_icon( - canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); - } - - for(int i = 0; i < world.enemies_count; i++) { - if(world.enemies[i].level > 0) { - canvas_draw_icon( - canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); - } else { - if(world.enemies[i].side) { - canvas_draw_icon( - canvas, - world.enemies[i].x * 10 + 4, - world.enemies[i].y * 10 + 2, - &I_enemyright); - } else { - canvas_draw_icon( - canvas, - world.enemies[i].x * 10 + 4, - world.enemies[i].y * 10 + 2, - &I_enemyleft); - } - } - } - } else { - canvas_set_font(canvas, FontPrimary); - if(world.player->x == world.endx && world.player->y == world.endy) { - if(world.level == 20) { - canvas_draw_str(canvas, 30, 35, "You win!"); - }else{ - canvas_draw_str(canvas, 30, 35, "Next level!"); - char str[20]; - intToStr(world.level, str); - canvas_draw_str(canvas, 90, 35, str); - } - - } else { - canvas_draw_str(canvas, 30, 35, "You died :("); - } - } - - furi_mutex_release(bomber_state->mutex); -} - -static void input_callback(InputEvent* input_event, void* ctx) { - // Проверяем, что контекст не нулевой - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -int32_t bomberduck_app(void* p) { - UNUSED(p); - - // Текущее событие типа InputEvent - InputEvent event; - // Очередь событий на 8 элементов размера InputEvent - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - BomberState* bomber_state = malloc(sizeof(BomberState)); - - bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex - if(!bomber_state->mutex) { - FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(bomber_state); - return 255; - } - - DOLPHIN_DEED(DolphinDeedPluginGameStart); - // Создаем новый view port - ViewPort* view_port = view_port_alloc(); - // Создаем callback отрисовки, без контекста - view_port_draw_callback_set(view_port, draw_callback, bomber_state); - // Создаем callback нажатий на клавиши, в качестве контекста передаем - // нашу очередь сообщений, чтоб запихивать в неё эти события - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Создаем GUI приложения - Gui* gui = furi_record_open(RECORD_GUI); - // Подключаем view port к GUI в полноэкранном режиме - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message_block(notification, &sequence_display_backlight_enforce_on); - - init(); - - // Бесконечный цикл обработки очереди событий - while(1) { - if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { - furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); - // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения - - if(event.type == InputTypePress) { - if(event.key == InputKeyOk) { - if(world.running) { - if(world.matrix[world.player->y][world.player->x] == 0 && - world.bombs_count < 2) { - notification_message(notification, &bomb2); - world.matrix[world.player->y][world.player->x] = 3; - Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; - world.bombs[world.bombs_count] = bomb; - world.bombs_count++; - } - } else { - init(); - } - } - if(world.running) { - if(event.key == InputKeyUp) { - if(world.player->y > 0 && - world.matrix[world.player->y - 1][world.player->x] == 0) - world.player->y--; - } - if(event.key == InputKeyDown) { - if(world.player->y < WorldSizeY - 1 && - world.matrix[world.player->y + 1][world.player->x] == 0) - world.player->y++; - } - if(event.key == InputKeyLeft) { - world.player->side = 0; - if(world.player->x > 0 && - world.matrix[world.player->y][world.player->x - 1] == 0) - world.player->x--; - } - if(event.key == InputKeyRight) { - world.player->side = 1; - if(world.player->x < WorldSizeX - 1 && - world.matrix[world.player->y][world.player->x + 1] == 0) - world.player->x++; - } - } - } else if(event.type == InputTypeLong) { - if(event.key == InputKeyBack) { - break; - } - } - } - if(world.running) { - if(world.player->x == world.endx && world.player->y == world.endy) { - notification_message(notification, &end); - world.running = 0; - world.level += 1; - if(world.level%5==0){ - DOLPHIN_DEED(DolphinDeedPluginGameWin); - } - } - for(int i = 0; i < world.bombs_count; i++) { - if(furi_get_tick() - world.bombs[i].planted > - (unsigned long)max((3000 - world.level * 150), 1000)) { - vibration = false; - world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; - notification_message(notification, &bomb_explore); - - for(int j = max(0, world.bombs[i].y - BombRange); - j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); - j++) { - if(world.matrix[j][world.bombs[i].x] != 2) { - world.matrix[j][world.bombs[i].x] = 6; - if(j == world.player->y && world.bombs[i].x == world.player->x) { - notification_message(notification, &end); - world.running = 0; - } - for(int e = 0; e < world.enemies_count; e++) { - if(j == world.enemies[e].y && - world.bombs[i].x == world.enemies[e].x) { - if(world.enemies[e].level > 0) { - world.enemies[e].level--; - } else { - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - } - } - - for(int j = max(0, world.bombs[i].x - BombRange); - j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); - j++) { - if(world.matrix[world.bombs[i].y][j] != 2) { - world.matrix[world.bombs[i].y][j] = 6; - if(world.bombs[i].y == world.player->y && j == world.player->x) { - notification_message(notification, &end); - world.running = 0; - } - for(int e = 0; e < world.enemies_count; e++) { - if(world.bombs[i].y == world.enemies[e].y && - j == world.enemies[e].x) { - if(world.enemies[e].level > 0) { - world.enemies[e].level--; - } else { - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - } - } - - for(int j = i; j < world.bombs_count - 1; j++) { - world.bombs[j] = world.bombs[j + 1]; - } - world.bombs_count--; - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; - vibration=true; - - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; - - } - } - for(int e = 0; e < world.enemies_count; e++) { - if(world.player->y == world.enemies[e].y && - world.player->x == world.enemies[e].x) { - notification_message(notification, &end); - world.running = 0; - } - } - - for(int e = 0; e < world.enemies_count; e++) { - if(world.enemies[e].level > 0) { - if(furi_get_tick() - world.enemies[e].last > - (unsigned long)max((2000 - world.level * 100), 1000)) { - world.enemies[e].last = furi_get_tick(); - int move = rand() % 4; - switch(move) { - case 0: - if(world.enemies[e].y > 0 && - world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) - world.enemies[e].y--; - break; - case 1: - if(world.enemies[e].y < WorldSizeY - 1 && - world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) - world.enemies[e].y++; - break; - case 2: - world.enemies[e].side = 0; - if(world.enemies[e].x > 0 && - world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) - world.enemies[e].x--; - break; - case 3: - world.enemies[e].side = 1; - if(world.enemies[e].x < WorldSizeX - 1 && - world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) - world.enemies[e].x++; - default: - break; - } - } - } else { - if(furi_get_tick() - world.enemies[e].last > - (unsigned long)max((1000 - world.level * 50), 500)) { - world.enemies[e].last = furi_get_tick(); - int move = rand() % 4; - switch(move) { - case 0: - if(world.enemies[e].y > 0 && - world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) - world.enemies[e].y--; - break; - case 1: - if(world.enemies[e].y < WorldSizeY - 1 && - world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) - world.enemies[e].y++; - break; - case 2: - world.enemies[e].side = 0; - if(world.enemies[e].x > 0 && - world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) - world.enemies[e].x--; - break; - case 3: - world.enemies[e].side = 1; - if(world.enemies[e].x < WorldSizeX - 1 && - world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) - world.enemies[e].x++; - default: - break; - } - } - } - } - for(int e = 0; e < world.enemies_count; e++) { - for(int h = e + 1; h < world.enemies_count; h++) { - if(world.enemies[e].y == world.enemies[h].y && - world.enemies[e].x == world.enemies[h].x) { - world.enemies[h].level++; - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - if(vibration){ - notification_message(notification, &vibr1); - } - } - - view_port_update(view_port); - furi_mutex_release(bomber_state->mutex); - } - - // Return to normal backlight settings - notification_message_block(notification, &sequence_display_backlight_enforce_auto); - furi_record_close(RECORD_NOTIFICATION); - // Специальная очистка памяти, занимаемой очередью - furi_message_queue_free(event_queue); - - // Чистим созданные объекты, связанные с интерфейсом - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - - furi_mutex_free(bomber_state->mutex); - furi_record_close(RECORD_GUI); - free(bomber_state); - - return 0; -} From 099f907972beaf3736a7348be665b64d4ffa14a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:39:37 +0300 Subject: [PATCH 062/216] Add files via upload --- applications/external/bomberduck/LICENSE | 22 + applications/external/bomberduck/README.md | 2 + .../external/bomberduck/application.fam | 15 + .../external/bomberduck/assets/bomb0.png | Bin 0 -> 4536 bytes .../external/bomberduck/assets/bomb1.png | Bin 0 -> 4529 bytes .../external/bomberduck/assets/bomb2.png | Bin 0 -> 4531 bytes .../external/bomberduck/assets/box.png | Bin 0 -> 4329 bytes .../external/bomberduck/assets/end.png | Bin 0 -> 4739 bytes .../external/bomberduck/assets/enemy1.png | Bin 0 -> 4757 bytes .../external/bomberduck/assets/enemyleft.png | Bin 0 -> 4761 bytes .../external/bomberduck/assets/enemyright.png | Bin 0 -> 4536 bytes .../external/bomberduck/assets/explore.png | Bin 0 -> 4540 bytes .../external/bomberduck/assets/playerleft.png | Bin 0 -> 4311 bytes .../bomberduck/assets/playerright.png | Bin 0 -> 4307 bytes .../external/bomberduck/assets/unbreakbox.png | Bin 0 -> 4763 bytes applications/external/bomberduck/bomb.png | Bin 0 -> 4534 bytes applications/external/bomberduck/bomberduck.c | 645 ++++++++++++++++++ 17 files changed, 684 insertions(+) create mode 100644 applications/external/bomberduck/LICENSE create mode 100644 applications/external/bomberduck/README.md create mode 100644 applications/external/bomberduck/application.fam create mode 100644 applications/external/bomberduck/assets/bomb0.png create mode 100644 applications/external/bomberduck/assets/bomb1.png create mode 100644 applications/external/bomberduck/assets/bomb2.png create mode 100644 applications/external/bomberduck/assets/box.png create mode 100644 applications/external/bomberduck/assets/end.png create mode 100644 applications/external/bomberduck/assets/enemy1.png create mode 100644 applications/external/bomberduck/assets/enemyleft.png create mode 100644 applications/external/bomberduck/assets/enemyright.png create mode 100644 applications/external/bomberduck/assets/explore.png create mode 100644 applications/external/bomberduck/assets/playerleft.png create mode 100644 applications/external/bomberduck/assets/playerright.png create mode 100644 applications/external/bomberduck/assets/unbreakbox.png create mode 100644 applications/external/bomberduck/bomb.png create mode 100644 applications/external/bomberduck/bomberduck.c diff --git a/applications/external/bomberduck/LICENSE b/applications/external/bomberduck/LICENSE new file mode 100644 index 000000000..bce361a99 --- /dev/null +++ b/applications/external/bomberduck/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/applications/external/bomberduck/README.md b/applications/external/bomberduck/README.md new file mode 100644 index 000000000..2d133145a --- /dev/null +++ b/applications/external/bomberduck/README.md @@ -0,0 +1,2 @@ +# flipperzero-bomberduck +Bomberman clone on flipper zero! diff --git a/applications/external/bomberduck/application.fam b/applications/external/bomberduck/application.fam new file mode 100644 index 000000000..afcd5a6ee --- /dev/null +++ b/applications/external/bomberduck/application.fam @@ -0,0 +1,15 @@ +App( + appid="bomberduck", + name="Bomberduck", + apptype=FlipperAppType.EXTERNAL, + entry_point="bomberduck_app", + cdefines=["BOMBERDUCK"], + requires=[ + "gui", + ], + stack_size=1 * 1024, + order=90, + fap_icon="bomb.png", + fap_category="Games", + fap_icon_assets="assets", +) diff --git a/applications/external/bomberduck/assets/bomb0.png b/applications/external/bomberduck/assets/bomb0.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdc3a3c12c7ede770e1c99c2003c777b03f4d75 GIT binary patch literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/bomb1.png b/applications/external/bomberduck/assets/bomb1.png new file mode 100644 index 0000000000000000000000000000000000000000..11d05b9b7c445452253792c5a51ad6448cca8aee GIT binary patch literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/bomb2.png b/applications/external/bomberduck/assets/bomb2.png new file mode 100644 index 0000000000000000000000000000000000000000..38ce7c732bfa5e3586d1c9b9a754b85405cd4566 GIT binary patch literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 zmV1XgTMc#X89QHDSYsLZ;Eip?zDuDazMnbho_o`dKC?ON)Zz6(Vr-zHP8ftfT+~0UY?>&{B)Aq|tz7sb~K6-mW>0A5f zzg)ga`Wu$MC-c$Ot2Uf1ICkwN`u6i(&STi{h11<%>*4a^4JQb*;G_-DjB@{Y~GX07XI+&jiGnm9m+u7+OqYup4iZn!)Gr} zGxskghU;}tTzrz~e7%$8SFf3S;YQ`c6^~p$>iFZ$zcwEGR@cMxKi=Cx@Q0QTRt}!% zs&A`qw0G8@+Wcsd<2&8=>|JrTx#iX$&JMizdviNaTMN>^ao@bi3%?<9e)7PLRTb`D z<;^tGbn@^^_VT9e@^|*P;y>y+c(A2NUNm>@uEqDdvyKOoSNj(=J(T%sUj66qF29rX z8n$oC*ZXEKqyAa^#O(eXd+xSfkN)abN6T|d>XS3DGq;KPv*NXzy3VvVM9x*{hZ}2i ze)kWoul9p&-Q_4M&H5~yoYseW`;$%a@88LE*+9W3Jxe~R9=QF~D{JO`c3J=JlTop2 z_u+Lq;c9kua(cRc*rdHh`>3GJFH&Z8*_m&p|C~*+iQyaY)v^! zamMxQ42}d12_isYkVGULmFa}jsPWRUt(q|-qCu2$r!nC5Audq@h{a?v;b?wBs3MK) z42VPGc)G;BX_NxKIgMqC5~DFJ9*>*iW|Js|FoL2e3@0&?L?Hr|tD_2&K%??Xm12a$ z4P;glVu~O}5tWk(ij|7fXoUU9SbUL~*E>!hl}A;8dSD4Ah7l$li$t)=9jpYw2(-2Erf$p)wqmm@;I6$LkySP$dWn zk(lNM#h!vx1b#xSDY2m)?z1ZRthC? zibX99V?%>x!iMsUg=EZDU}q_662&%2fK|zaCr71Hagd4vI0%~U0HuPA1+@TcE=mCo z@>wV|p9}CH$1)lf$I_cbDZ;?%6e3IrV6kXO>re%!H~KtIBWc1XEWR+K@X*0&+$uyX z6B8YNAp*85jH)JKvy-_LZp$Tb_#nv%P$`gPScxhpft$=0tw)^}8YTmUWz;%_1ezV@ zLc1iuD5B&S#jw+;hJ>h|8PsDNdSc+(MI-pTub^K@)fm4lR@LA}8?G z{|l`y9>g&+<%NO_$FJ5*BP(hIk)h z<*8|fWN8z%W-2;f2Gm)Af}ywtoe+!|6$~3q7*qF*v5Xzqe`(^-0FyQu=r>}6n-|;* zvGL7tR5Nwk`3gUybMY090I6pNnU=mYa?Qv!Ed{0po~f=Gxu&JSw7@gf^?#GgFmas% zQFsc9!^_gAH7PcD(V89HQsCCET)Ka|&V3KI=Ee#imUTMQO7)kNXj)$djdK)_H-FBR zSs9DX^M)S0dBQaH zlF4IiN?T%=QXmAF5>khuB+w?ABtw&-4MQMFO-egsU})OldTbuSv=C^fWD2hPog}}e znaOw>`j<5$>AU@Qf4lqJ-TUsItzKR+EqhKjf*{lUmA)GIZ?3Z^XTsmi>R=!I`}_LZ zpi#re(U_*nN*JIo zICuO{Iol7PyT13C>066Ceo^!0<*Hm=S0)!v+kFJQ5&h9ypWQiex&dv@d#s{w#upO{ z$ck&^#y|e+(8{b&as#&(wPlo)-C*Y|?GNWoeeOf)d%cV4ntPTwZx-f**Dl_8tD*hC znMVR`7m9Q;IJ3C$!JcAi!tJ#=FWt6weJdcg&x&0Nz0$lrd~)gQ2c5yb_Jh;9o_MIJ z{ijcA1x($Qw)syLE@*z|!=GRM^_>3mr+&K+zxiTlzpL~2@rg68xxRrQ89z|G-fF+s zJD503chA#XJ(b577QFxX>7@@9PjAd!*-`z%-?}ID1P@hj%-;WS-PvOoI&<3n-fcZS z3*NrB;7;(D+}rM}eci>AH+&m?)xNydUehzMZE;(E&QEUNxYpHsZ7zD|qbkNiEgf-)oybv+aH7^MBd3W9p7X ztNW#w=Ukk!X6HBm@W`IC+79M=$K&}Y>pxny_5iyn>)zKl<@tX1vS0zhO`Qj~3f92w zbvXmgy(_jZyYJk@eD>1Hmh6rj-yb-3J$mZB3mboy*J_!IAMPhJv*ImFP8~kFC30k4 z<`*xv-2bbKubpYxy`r-o!?di=qn26cut1l^9&i5l{70$pR@^+Dmp!4o|HtnZP5S(N z=J`WW_0-dQN|D)p#Z8uig3Nv8Cm;JqA|85D9oVb<^OmKfUh8=71I<8?oKgjLVlYs} ziE6~oOR50uiAW5#D1wxfC1Si-4-8ZQAtmauUO#fwiYk)Fx|#_PftVN6DV6IruxkDC zT5)~7$V%3-((IB12LU3$;L$`R9M!pm$C||D;Mx@9Ry3(%)O)PKKsD-BHGtA~+D>5Q z38j&;mS&?Rnj~{Iz9nf0c;&Iy8Ago5@pwFLk2~zD7Q#uEWpRSSDGGxcnBEjM_yiW! zZ6-tt!v}OxQ(}gqMo|-!7t{vBW3|G4bTGb1ED#uikLqa_ARl;wkKv@9z#|cSq=jyj zH$sqfKwoO1*TR9uYk;mcXd)|+gDIGK(l;vftnP*sOs$x$vV{DJBr z3zLG75{V_PAlaid4MiR%YgBCJPBNX5fk5*i+)>(txhIvORv^InRI$Mf&+qeCP5+#v zii*S~m$V?bM4q8BmZT|+cDbAwOEYjKxFu0$c$Yx)BcS|I-Qc4lFrgs0U4b}m2kT-b zH;GXqAz?HnIx)B8ggCq?5rmTl0^=9~u|iW|SMuSJQJGMZ2}QC3OR)?lxG4goS%|_* zZXN@Gkttc^ouZtAl02yC1tpg9LoOVS)cag^(R0!l{ctCAu& zeU-L3JZMR(D7kdkpitkjlR$45f| z-aXRoIw)7Zq!mb6qGT8CzyyJSJtR9|{T#9bbCR-5QiMPO(lr`gS7js4YhY0b@(8(t z?V02XU63qP(P-^>9Wbi^3Bw2)qu5%CrXQvcK92KzoDH%M1;E9G09ck&dFb|Kr_(@OHUGxB< z$DNFc-*LLe=^7IQV^SXPu5r4?#K4%8$Ghumqbqy(r5Hrvvuqr`@*XYn9fhyU_rxmK z=m=uBncs}W{<20WoMiX|<&!RF&6|=r_pgU9RYB2gqdaJM)rk2fg(M&FfrQ2tqYgD6 z@K?7?p9PhQ{JurC`KQG@0|R9ii^XQMZOq7s*{8gbYniyPa^IC761(z0+t6O`Ms^D` W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/enemy1.png b/applications/external/bomberduck/assets/enemy1.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee7cb27f1ee52c63dbdb31e788c1011c8448d35 GIT binary patch literal 4757 zcmeHKeQ*?K8DDZ~L(Y;gZ3+PcEO&er*xQfW``9&?K<|#^AV-dH&@fWl{dhOoCU<-6 zZE_bZ*aSL45F@leGo)0-Rw9ayb$|>CLJb-!%7ii~TFfL=FfhR&18RWy?p;2$Gfu|h zU%8pvefNEz=l4F(@A)pRO1up-nWJ}%r-V}HSO=6USEIgpYbb4+b>@E zS<&G)*B_sLVe2bc#;Npmt+~hCH!7Z;_4=Kh8{Veg#)TK=ocQt6flKc#ckO-Um*FLA zmKR=I+AO`icGi~pug;ybq^02C&13Atrt_|Y`M2_ayL{H=y4d8ddv~`W$b{Erw>#i- zy9YCe`8I9ZRa@ZgTODbgrH2Dsjqk24zjXRqd*-)%?%kc8 z3yx38c~JU&_PFzAcgMnsb+gbTmX-CElFt6!&+o|2{CZz+&(*G;8R$nJ7TFBsl1q!t zZ*SZ2`#;uazv@LkxN&Ck*|}2p`^~|p4|Ls}nRoK4w`TACmi&T--HvG;&ukZp9E&@v zI{)Hdas8*oInrF;?7aCitvBj^(Xf8si<`UFYo#5HocWCd=8R`{wA%On;jKMS?TObr zzkO)>C!brl@7dpcvFVb!$9B8zrR;MRAFf#cU1nSAlpk%&^8D%$Zvds++P}ApH~ITE zWcI(-RlIA(yvt8!Gk;!HYi#S?(trAP`23k`TlZ(x8)o1~ACf7lvD#(lkDh7>o!F4_ z_jhU+{os=yepK67++KlUYU+1KOo<`Z)mGf+ul5@Y6y~S!U+{XLwQgphh3)ICr+7AS#+6Ru=xpp#0|>j!i_3ey>Vqw z*jOPjqA5Smm>XvyKnQ3Y8V^;5qioz|O5n1vt#{)lG-0AuxJ;$~0P0p$fYKJ)LSWvw zTuqtsjA*VZN^FT|*#HE5a+%6CEyCh>EEcoGtQJKr!%2o=aDu`q3WF9{v?i=^aV#7) z>kvr{4~Pn?9MNPYjOv&iuT*I+lL?NagYktTe*X}BI6A-rJP zdFT|B$)QNX3z9v`Qj?`&vPQ+Gk0jC=83=SA!X0Hjn0vw)TKWB~M-i&@@O&PZNuQq; z6+sr+M3d%uhrrorj3H?Xqa6-A#?Us{;+>)(**FJJb0eU9;i$%i1)xJgaElCa7~V=z zq}7f&MTy5~jDDTlZ+fJee*i2_LlNl79pf~NrK7>yoPBrV3N zU}+iT5po6PncxatkSNr1qpf4*K(7KM3?pcaVuBROLh>kbfH3^=r)VVzhNgG{qe&59 zw37pv(+&Ve0-mu`a4C@vVRX>{ONvkv1j*WLEJ^(TQY0KApeY9|n;p;?P16j<(T43{CTZ`b<;QWp8JRf2(3HuD|&Qb(@R-hq99fBen`y{bV29g5ZvZ4{d1!vd}k= z$M_pqQIBy32t7W@nD`y1Yn-kzF)$|MadnN;H6{keWIV2}&x|hP@Szxl;kRrI9(m91 z+!Ju^G3);c@ptp9VP~4=^Lx{-r_MCanUH>X^<>yJP4kv&ZY89jq>#i1 zJ`mBEtd*ns2mTAS8B?JV>+>uPW?vK@^!Mi*3`zp7Upp$8Is*uW+&NA zL`zbs0ctr=!Fn1&i)p1&>CqOo0Vx97=)qb7$0un_px98QP>LKC(mS(BNUZ1dY(=+GA znVDZy?BQN?p6lz*o76lTeHJg>h?n>DZ(X=4efp0-zwk*{?hH)X*X{=YTy3;Pq$6kme}b0 z`O_I^zFGO`EpL9e^`y4VcD`d}`s+1sELrhOSIhXBziCPH{_$xc6;!kw|J4@38u)z8 z^!|0dWm}fq@%Dst*I$=5SvoHKp#RYM$gx*WKlrn>jj6X0`>s+cj_o_RIo!S` z<;u>cJAZv)-olB3^Z$+P_1&{Ap@Ojn?tVtD24=(+d=+#EL)( zC#qqbmsA1ZiEtE36hZO}6H#8Q0XiyxDkb8!o^L;BMHR_yy~h?H15ppCR*D-nu&l8( zBsSKFF3DP0V98H#5FiY69!-R6BQY-Fwwkyc92;iBikdEZjoVrg2%;WU11O8LIEncZ zNLJKLLSGpX3&Dma%0W!6(?sB_2N6AcID{k)#YgM3TC*HUBtR_)L)REwl^U^Rkv|X| ziZCdsQo>O)3X(m-Q&;5cWR1wpm@&&4o(K#d!X4o~Si9*Ay#fKwtBQ3-dVa6lYOK#m zs;EeuIb;RFA@VjBb5Sgfu?~kFbFnr!5}cAK+jxh-^24C~k(ka$L|{Nca9n{nA`G&V z62K@%qA*q_X-u&53`UbK$tg>eNQ$;$5M`PIRms;5&&q(3Ae57G2`<`Y!vrTyVyw$< z$9T!fV*uD>S{8Y`C^IIMByx*XEzHC1RKk1}Afk~fbHX5;TM+cStu#(vw*+f>U4{W} zYl#x6OI)7_DPgco=M6R~yOVa>NRp;)b{FML=4|5K4YU|kqJc?~IK!IZ#l&rjwU&pzLSKO zVg9P5$PNF^+h`s%Ke^?_N(`>wV49L0wG6CDUL`MU6|;+E1trfq zd4M_X0E!<7E;|idiE@Y|lm0p-LQRkqXR~n>`Tr}?Ns9tWIc3l&uKd_7WgmLE|)NMZTAIeTT40}|--A~%!BM3gxh@nT?fGl9X zH}W&kQ8#i46dhY+RQ!(7HAdH{7#NlFn7YR38WjVhavoFH|BNon^+Pd;z<1d=Jo28> z+uPxBd2+P4GKL^{w(%X8Xe+FT#)-N=;G1}Me3m6`=3NEdw?oq`-B+P|)Ua`qLd+L@ zAfa(ZuSSg*{Ck?F-3pxw{oVzk^v;I^)C>fjl+xc{m669NElsJuryxeLkp0ky?W+$H z<$LPBbHK8C--2@XFP+ye&RBVdIlcCpy8(G;UQuW0oz(9`D8%n8^*+0BRr9|AWQvH3 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/enemyright.png b/applications/external/bomberduck/assets/enemyright.png new file mode 100644 index 0000000000000000000000000000000000000000..45e6a861ad9c914af25be2b6c1b6097fdc6f0d17 GIT binary patch literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/explore.png b/applications/external/bomberduck/assets/explore.png new file mode 100644 index 0000000000000000000000000000000000000000..5eb50b669b3ee364bd25a37991519cf833660ae5 GIT binary patch literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/playerleft.png b/applications/external/bomberduck/assets/playerleft.png new file mode 100644 index 0000000000000000000000000000000000000000..86997a985eab4de991e315858b17ed7e0a981f74 GIT binary patch literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/playerright.png b/applications/external/bomberduck/assets/playerright.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6283d9c26d9f9582fecd0cef9765ab2b288576 GIT binary patch literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/unbreakbox.png b/applications/external/bomberduck/assets/unbreakbox.png new file mode 100644 index 0000000000000000000000000000000000000000..5e65912d53405d04bcd05916947a8de8fc5239c8 GIT binary patch literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/bomb.png b/applications/external/bomberduck/bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..44b9bfdeae76553be52ce1c451133a4baee7bf68 GIT binary patch literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/bomberduck.c b/applications/external/bomberduck/bomberduck.c new file mode 100644 index 000000000..7b8b5f14a --- /dev/null +++ b/applications/external/bomberduck/bomberduck.c @@ -0,0 +1,645 @@ +#include +#include + +#include +#include +#include +#include +#include +#include "bomberduck_icons.h" +#include + +int max(int a, int b) { + return (a > b) ? a : b; +} + +int min(int a, int b) { + return (a < b) ? a : b; +} + +#define WorldSizeX 12 +#define WorldSizeY 6 +#define BombRange 1 + + +typedef struct { + FuriMutex* mutex; +} BomberState; + +typedef struct { + int row; + int col; +} Cell; + +typedef struct { + Cell cells[WorldSizeY * WorldSizeX]; + int front; + int rear; +} Queue; + +void enqueue(Queue* q, Cell c) { + q->cells[q->rear] = c; + q->rear++; +} + +Cell dequeue(Queue* q) { + Cell c = q->cells[q->front]; + q->front++; + + return c; +} + +bool is_empty(Queue* q) { + return q->front == q->rear; +} + +typedef struct { + int x; + int y; + int planted; +} Bomb; + +typedef struct { + int x; + int y; + bool side; +} Player; + +typedef struct { + int x; + int y; + int last; + bool side; + int level; +} Enemy; + +typedef struct { + int matrix[WorldSizeY][WorldSizeX]; + Player* player; + bool running; + int level; + + Enemy enemies[10]; + int enemies_count; + + Bomb bombs[100]; + int bombs_count; + + int endx; + int endy; +} World; + +Player player = {0, 0, 1}; +World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; +bool vibration = false; + +void init() { + player.x = 1; + player.y = 1; + + world.endx = 4 + rand() % 8; + world.endy = rand() % 6; + for(int i = 0; i < WorldSizeY; i++) { + for(int j = 0; j < WorldSizeX; j++) { + world.matrix[i][j] = rand() % 3; + } + } + world.running = 1; + world.bombs_count =0; + vibration = false; + for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { + world.matrix[j][player.x] = 0; + } + + for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { + world.matrix[player.y][j] = 0; + } + + world.enemies_count = 0; + for(int j = 0; j < rand() % 4 + world.level / 5; j++) { + Enemy enemy; + enemy.x = 4 + rand() % 7; + enemy.y = rand() % 6; + enemy.last = 0; + enemy.side = 1; + enemy.level = 0; + + world.enemies[j] = enemy; + world.enemies_count++; + + for(int m = max(0, world.enemies[j].y - BombRange); + m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); + m++) { + world.matrix[m][world.enemies[j].x] = 0; + } + + for(int m = max(0, world.enemies[j].x - BombRange); + m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); + m++) { + world.matrix[world.enemies[j].y][m] = 0; + } + } + world.matrix[world.endy][world.endx] = 1; +} + +const NotificationSequence end = { + &message_vibro_on, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb2 = { + &message_vibro_on, + &message_delay_25, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb_explore = { + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence vibr1 = { + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + + NULL, +}; + + +void intToStr(int num, char* str) { + int i = 0, sign = 0; + + if(num < 0) { + num = -num; + sign = 1; + } + + do { + str[i++] = num % 10 + '0'; + num /= 10; + } while(num > 0); + + if(sign) { + str[i++] = '-'; + } + + str[i] = '\0'; + + // Reverse the string + int j, len = i; + char temp; + for(j = 0; j < len / 2; j++) { + temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} + +bool BFS() { + // Initialize visited array and queue + int visited[WorldSizeY][WorldSizeX] = {0}; + Queue q = {.front = 0, .rear = 0}; + // Mark the starting cell as visited and enqueue it + visited[world.player->y][world.player->x] = 1; + Cell startCell = {.row = world.player->y, .col = world.player->x}; + enqueue(&q, startCell); + // Traverse the field + while(!is_empty(&q)) { + // Dequeue a cell from the queue + Cell currentCell = dequeue(&q); + // Check if the current cell is the destination cell + if(currentCell.row == world.endy && currentCell.col == world.endx) { + return true; + } + // Check the neighboring cells + for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { + for(int colOffset = -1; colOffset <= 1; colOffset++) { + // Skip diagonals and the current cell + if(rowOffset == 0 && colOffset == 0) { + continue; + } + if(rowOffset != 0 && colOffset != 0) { + continue; + } + // Calculate the row and column of the neighboring cell + int neighborRow = currentCell.row + rowOffset; + int neighborCol = currentCell.col + colOffset; + // Skip out-of-bounds cells and already visited cells + if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || + neighborCol >= WorldSizeX) { + continue; + } + if(visited[neighborRow][neighborCol]) { + continue; + } + // Mark the neighboring cell as visited and enqueue it + if(world.matrix[neighborRow][neighborCol] != 2) { + visited[neighborRow][neighborCol] = 1; + Cell neighborCell = {.row = neighborRow, .col = neighborCol}; + enqueue(&q, neighborCell); + } + } + } + } + return false; +} + +static void draw_callback(Canvas* canvas, void* ctx) { + furi_assert(ctx); + const BomberState* bomber_state = ctx; + + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + if(!BFS()) { + init(); + } + canvas_clear(canvas); + + canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); + + if(world.running) { + for(size_t i = 0; i < WorldSizeY; i++) { + for(size_t j = 0; j < WorldSizeX; j++) { + switch(world.matrix[i][j]) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); + break; + case 2: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); + break; + case 3: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); + break; + case 4: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); + break; + case 5: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); + break; + case 6: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); + world.matrix[i][j] = 0; + break; + } + } + } + + if(world.player->side) { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); + } else { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); + } + + for(int i = 0; i < world.enemies_count; i++) { + if(world.enemies[i].level > 0) { + canvas_draw_icon( + canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); + } else { + if(world.enemies[i].side) { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyright); + } else { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyleft); + } + } + } + } else { + canvas_set_font(canvas, FontPrimary); + if(world.player->x == world.endx && world.player->y == world.endy) { + if(world.level == 20) { + canvas_draw_str(canvas, 30, 35, "You win!"); + }else{ + canvas_draw_str(canvas, 30, 35, "Next level!"); + char str[20]; + intToStr(world.level, str); + canvas_draw_str(canvas, 90, 35, str); + } + + } else { + canvas_draw_str(canvas, 30, 35, "You died :("); + } + } + + furi_mutex_release(bomber_state->mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + // Проверяем, что контекст не нулевой + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + + furi_message_queue_put(event_queue, input_event, FuriWaitForever); +} + +int32_t bomberduck_app(void* p) { + UNUSED(p); + + // Текущее событие типа InputEvent + InputEvent event; + // Очередь событий на 8 элементов размера InputEvent + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + BomberState* bomber_state = malloc(sizeof(BomberState)); + + bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex + if(!bomber_state->mutex) { + FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + free(bomber_state); + return 255; + } + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + // Создаем новый view port + ViewPort* view_port = view_port_alloc(); + // Создаем callback отрисовки, без контекста + view_port_draw_callback_set(view_port, draw_callback, bomber_state); + // Создаем callback нажатий на клавиши, в качестве контекста передаем + // нашу очередь сообщений, чтоб запихивать в неё эти события + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Создаем GUI приложения + Gui* gui = furi_record_open(RECORD_GUI); + // Подключаем view port к GUI в полноэкранном режиме + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message_block(notification, &sequence_display_backlight_enforce_on); + + init(); + + // Бесконечный цикл обработки очереди событий + while(1) { + if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения + + if(event.type == InputTypePress) { + if(event.key == InputKeyOk) { + if(world.running) { + if(world.matrix[world.player->y][world.player->x] == 0 && + world.bombs_count < 2) { + notification_message(notification, &bomb2); + world.matrix[world.player->y][world.player->x] = 3; + Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; + world.bombs[world.bombs_count] = bomb; + world.bombs_count++; + } + } else { + init(); + } + } + if(world.running) { + if(event.key == InputKeyUp) { + if(world.player->y > 0 && + world.matrix[world.player->y - 1][world.player->x] == 0) + world.player->y--; + } + if(event.key == InputKeyDown) { + if(world.player->y < WorldSizeY - 1 && + world.matrix[world.player->y + 1][world.player->x] == 0) + world.player->y++; + } + if(event.key == InputKeyLeft) { + world.player->side = 0; + if(world.player->x > 0 && + world.matrix[world.player->y][world.player->x - 1] == 0) + world.player->x--; + } + if(event.key == InputKeyRight) { + world.player->side = 1; + if(world.player->x < WorldSizeX - 1 && + world.matrix[world.player->y][world.player->x + 1] == 0) + world.player->x++; + } + } + } else if(event.type == InputTypeLong) { + if(event.key == InputKeyBack) { + break; + } + } + } + if(world.running) { + if(world.player->x == world.endx && world.player->y == world.endy) { + notification_message(notification, &end); + world.running = 0; + world.level += 1; + if(world.level%5==0){ + DOLPHIN_DEED(DolphinDeedPluginGameWin); + } + } + for(int i = 0; i < world.bombs_count; i++) { + if(furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150), 1000)) { + vibration = false; + world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; + notification_message(notification, &bomb_explore); + + for(int j = max(0, world.bombs[i].y - BombRange); + j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); + j++) { + if(world.matrix[j][world.bombs[i].x] != 2) { + world.matrix[j][world.bombs[i].x] = 6; + if(j == world.player->y && world.bombs[i].x == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(j == world.enemies[e].y && + world.bombs[i].x == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = max(0, world.bombs[i].x - BombRange); + j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); + j++) { + if(world.matrix[world.bombs[i].y][j] != 2) { + world.matrix[world.bombs[i].y][j] = 6; + if(world.bombs[i].y == world.player->y && j == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.bombs[i].y == world.enemies[e].y && + j == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = i; j < world.bombs_count - 1; j++) { + world.bombs[j] = world.bombs[j + 1]; + } + world.bombs_count--; + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration=true; + + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; + + } + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.player->y == world.enemies[e].y && + world.player->x == world.enemies[e].x) { + notification_message(notification, &end); + world.running = 0; + } + } + + for(int e = 0; e < world.enemies_count; e++) { + if(world.enemies[e].level > 0) { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((2000 - world.level * 100), 1000)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) + world.enemies[e].x++; + default: + break; + } + } + } else { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((1000 - world.level * 50), 500)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) + world.enemies[e].x++; + default: + break; + } + } + } + } + for(int e = 0; e < world.enemies_count; e++) { + for(int h = e + 1; h < world.enemies_count; h++) { + if(world.enemies[e].y == world.enemies[h].y && + world.enemies[e].x == world.enemies[h].x) { + world.enemies[h].level++; + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + if(vibration){ + notification_message(notification, &vibr1); + } + } + + view_port_update(view_port); + furi_mutex_release(bomber_state->mutex); + } + + // Return to normal backlight settings + notification_message_block(notification, &sequence_display_backlight_enforce_auto); + furi_record_close(RECORD_NOTIFICATION); + // Специальная очистка памяти, занимаемой очередью + furi_message_queue_free(event_queue); + + // Чистим созданные объекты, связанные с интерфейсом + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + + furi_mutex_free(bomber_state->mutex); + furi_record_close(RECORD_GUI); + free(bomber_state); + + return 0; +} From 13a65d45a37549a2373c17c3cd590abfdde42160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:46:10 +0300 Subject: [PATCH 063/216] Update LICENSE --- applications/external/bomberduck/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/bomberduck/LICENSE b/applications/external/bomberduck/LICENSE index bce361a99..4624b249c 100644 --- a/applications/external/bomberduck/LICENSE +++ b/applications/external/bomberduck/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) [year] [fullname] +Copyright (c) 2023 лень Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From d01600ea0fc01b4db8f63d7e20f4a5b838865a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:46:27 +0300 Subject: [PATCH 064/216] Update application.fam --- applications/external/bomberduck/application.fam | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/external/bomberduck/application.fam b/applications/external/bomberduck/application.fam index afcd5a6ee..2f8246af9 100644 --- a/applications/external/bomberduck/application.fam +++ b/applications/external/bomberduck/application.fam @@ -3,7 +3,6 @@ App( name="Bomberduck", apptype=FlipperAppType.EXTERNAL, entry_point="bomberduck_app", - cdefines=["BOMBERDUCK"], requires=[ "gui", ], From 2eac821f7f485a7b3df0b1f08e3f0610453bcb94 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 20:53:09 +0300 Subject: [PATCH 065/216] Update readme --- ReadMe.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReadMe.md b/ReadMe.md index 1611bed67..91ca8235d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -176,6 +176,7 @@ Games: - Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games) - BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games) - 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game) +- Bomberduck [(by leo-need-more-coffee)](https://github.com/leo-need-more-coffee/flipperzero-bomberduck) # Instructions From 0ef37df4ae9b128f025a4b99ad63084c1e20519d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 20:55:09 +0300 Subject: [PATCH 066/216] Update TOTP / run fbt format --- applications/external/bomberduck/bomberduck.c | 35 ++++++++++--------- .../external/hid_app/views/hid_ytshorts.c | 1 - .../external/totp/workers/type_code_common.c | 13 ++++--- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/applications/external/bomberduck/bomberduck.c b/applications/external/bomberduck/bomberduck.c index 7b8b5f14a..2c1c2940a 100644 --- a/applications/external/bomberduck/bomberduck.c +++ b/applications/external/bomberduck/bomberduck.c @@ -21,7 +21,6 @@ int min(int a, int b) { #define WorldSizeY 6 #define BombRange 1 - typedef struct { FuriMutex* mutex; } BomberState; @@ -105,7 +104,7 @@ void init() { } } world.running = 1; - world.bombs_count =0; + world.bombs_count = 0; vibration = false; for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { world.matrix[j][player.x] = 0; @@ -191,7 +190,6 @@ static const NotificationSequence vibr1 = { NULL, }; - void intToStr(int num, char* str) { int i = 0, sign = 0; @@ -344,7 +342,7 @@ static void draw_callback(Canvas* canvas, void* ctx) { if(world.player->x == world.endx && world.player->y == world.endy) { if(world.level == 20) { canvas_draw_str(canvas, 30, 35, "You win!"); - }else{ + } else { canvas_draw_str(canvas, 30, 35, "Next level!"); char str[20]; intToStr(world.level, str); @@ -427,24 +425,24 @@ int32_t bomberduck_app(void* p) { if(world.running) { if(event.key == InputKeyUp) { if(world.player->y > 0 && - world.matrix[world.player->y - 1][world.player->x] == 0) + world.matrix[world.player->y - 1][world.player->x] == 0) world.player->y--; } if(event.key == InputKeyDown) { if(world.player->y < WorldSizeY - 1 && - world.matrix[world.player->y + 1][world.player->x] == 0) + world.matrix[world.player->y + 1][world.player->x] == 0) world.player->y++; } if(event.key == InputKeyLeft) { world.player->side = 0; if(world.player->x > 0 && - world.matrix[world.player->y][world.player->x - 1] == 0) + world.matrix[world.player->y][world.player->x - 1] == 0) world.player->x--; } if(event.key == InputKeyRight) { world.player->side = 1; if(world.player->x < WorldSizeX - 1 && - world.matrix[world.player->y][world.player->x + 1] == 0) + world.matrix[world.player->y][world.player->x + 1] == 0) world.player->x++; } } @@ -459,7 +457,7 @@ int32_t bomberduck_app(void* p) { notification_message(notification, &end); world.running = 0; world.level += 1; - if(world.level%5==0){ + if(world.level % 5 == 0) { DOLPHIN_DEED(DolphinDeedPluginGameWin); } } @@ -524,13 +522,18 @@ int32_t bomberduck_app(void* p) { world.bombs[j] = world.bombs[j + 1]; } world.bombs_count--; - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; - vibration=true; + } else if( + furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150) * 2 / 3, 666) && + world.matrix[world.bombs[i].y][world.bombs[i].x] != 5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration = true; - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; - + } else if( + furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150) / 3, 333) && + world.matrix[world.bombs[i].y][world.bombs[i].x] != 4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; } } for(int e = 0; e < world.enemies_count; e++) { @@ -618,7 +621,7 @@ int32_t bomberduck_app(void* p) { } } } - if(vibration){ + if(vibration) { notification_message(notification, &vibr1); } } diff --git a/applications/external/hid_app/views/hid_ytshorts.c b/applications/external/hid_app/views/hid_ytshorts.c index 9be2f853c..359091640 100644 --- a/applications/external/hid_app/views/hid_ytshorts.c +++ b/applications/external/hid_app/views/hid_ytshorts.c @@ -109,7 +109,6 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } - static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) { // Set cursor to the phone's left up corner // Delays to guarantee one packet per connection interval diff --git a/applications/external/totp/workers/type_code_common.c b/applications/external/totp/workers/type_code_common.c index 696df3b1f..bf5818ab2 100644 --- a/applications/external/totp/workers/type_code_common.c +++ b/applications/external/totp/workers/type_code_common.c @@ -30,7 +30,7 @@ static uint32_t get_keypress_delay(TokenAutomationFeature features) { } static void totp_type_code_worker_press_key( - uint8_t key, + uint16_t key, TOTP_AUTOMATION_KEY_HANDLER key_press_fn, TOTP_AUTOMATION_KEY_HANDLER key_release_fn, TokenAutomationFeature features) { @@ -47,8 +47,6 @@ void totp_type_code_worker_execute_automation( TokenAutomationFeature features) { furi_delay_ms(500); uint8_t i = 0; - totp_type_code_worker_press_key( - HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); while(i < code_buffer_size && code_buffer[i] != 0) { uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]); @@ -58,7 +56,11 @@ void totp_type_code_worker_execute_automation( if(char_index > 35) break; - uint8_t hid_kb_key = hid_number_keys[char_index]; + uint16_t hid_kb_key = hid_number_keys[char_index]; + if(char_index > 9) { + hid_kb_key |= KEY_MOD_LEFT_SHIFT; + } + totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features); furi_delay_ms(get_keystroke_delay(features)); i++; @@ -74,7 +76,4 @@ void totp_type_code_worker_execute_automation( furi_delay_ms(get_keystroke_delay(features)); totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features); } - - totp_type_code_worker_press_key( - HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); } \ No newline at end of file From fe6bf3c7d6fe6c10a3f915f4de8d8ea160b3272f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 02:25:52 +0300 Subject: [PATCH 067/216] Revert some changes --- lib/nfc/protocols/mifare_classic.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 204e3a5eb..d2d7467dc 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -892,25 +892,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { - if(mf_classic_is_key_found( - &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyA)) { - key = nfc_util_bytes2num(sector_trailer->key_a, 6); - access_key = MfClassicKeyA; - } else { - FURI_LOG_D(TAG, "Key not known"); - command_processed = true; - break; - } + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + access_key = MfClassicKeyA; } else { - if(mf_classic_is_key_found( - &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyB)) { - key = nfc_util_bytes2num(sector_trailer->key_b, 6); - access_key = MfClassicKeyB; - } else { - FURI_LOG_D(TAG, "Key not known"); - command_processed = true; - break; - } + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + access_key = MfClassicKeyB; } uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA; From e24cb944ff795387599abfa6d4895ffb1f522957 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 02:38:42 +0300 Subject: [PATCH 068/216] Temp fix desktop lock bug and update changelog --- CHANGELOG.md | 29 +++++-------------- .../desktop/views/desktop_view_locked.c | 3 +- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dfbf46cf..70948b2f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,12 @@ ### New changes -* Power + BLE: DeepSleep + required ble stack upgrade added back, all known issues was fixed in OFW, no issues was found during our tests -* Desktop: Allow locking without pin using Up menu on desktop (Short click on `Lock` = Without PIN / Long = With PIN) -* RFID: Add confirmation message before running `Clear T5577 Password` -* RFID: Add more user friendly RAW emulation via UI [(by Dan Caprita)](https://forum.flipperzero.one/t/electra-intercom/6368/43) -* SubGHz: Fixed `Frequency Analyzer` issues, fixed `Read` mode issues -* SubGHz: Fix NFC crash when using external CC1101 radio module -* SubGHz: Fix multiple external CC1101 radio module issues, (int callbacks, SPI handlers init/reinit) -* SubGHz: Using scene manager function in add manually (by @gid9798 | PR #437) -* Plugins: ESP32: WiFi Marauder - add icon for log files in logs browser -* Plugins: Update **ESP32: WiFi Marauder companion** plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) merged [PR by @tcpassos](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion/pull/11) +* NFC: Temp fix for Detect reader not collecting nonces +* Desktop: Temp fix for old backlight bug when locking by holding up arrow +* BLE Info: Show version instead of branch +* Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) +* Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit +* Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* Plugins: Fix RFID Fuzzer and iButton Fuzzer crashes -* Plugins: iButton Fuzzer default keys update (by @team-orangeBlue) -* Infrared: Updated infrared assets (by @amec0e | PR #441) -* Docs: Update **How To Install** images (by @krolchonok | PR #436) -* OFW PR 2620: NFC: Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (by Astrrra) -* OFW PR 2616: Picopass: remove spaces in CSN (by bettse) -* OFW PR 2604: WS: add protocol "Wendox W6726" (by Skorpionm) -* OFW PR 2607: BadUSB: command parser fix (by nminaylov) -* OFW: Keep HSI16 working in stop mode. -* OFW: FuriHal: use proper divider for core2 when transition to sleep, remove extra stop mode transition checks, cleanup code. Furi: proper assert and check messages. -* OFW: Don't reboot on crash in debug builds -* OFW: cubewb: downgraded to v1.15.0 +* Docs: Update HowToInstall (by @krolchonok | PR #443) #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/applications/services/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c index 0bf757036..8a0ddb3af 100644 --- a/applications/services/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -242,5 +242,6 @@ bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) DesktopViewLockedModel* model = view_get_model(locked_view->view); const DesktopViewLockedState view_state = model->view_state; view_commit_model(locked_view->view, false); - return view_state == DesktopViewLockedStateLockedHintShown; + return view_state == DesktopViewLockedStateLockedHintShown || + view_state == DesktopViewLockedStateLocked; } From b801f70f3a39139d443fba05655e3ad5e38f6769 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:01:50 +0300 Subject: [PATCH 069/216] OFW PR 2627: Add HID mouse auto-clicker by rwl4 --- applications/external/hid_app/hid.c | 21 ++ applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../hid_app/views/hid_mouse_clicker.c | 214 ++++++++++++++++++ .../hid_app/views/hid_mouse_clicker.h | 14 ++ 5 files changed, 252 insertions(+) create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.c create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index f29a3b22a..f6b853f9c 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -13,6 +13,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexTikTok, HidSubmenuIndexYTShorts, HidSubmenuIndexMouse, + HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, }; @@ -40,6 +41,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexYTShorts) { app->view_id = BtHidViewYTShorts; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts); + } else if(index == HidSubmenuIndexMouseClicker) { + app->view_id = HidViewMouseClicker; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); @@ -62,6 +66,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); + hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); hid_tiktok_set_connected_status(hid->hid_tiktok, connected); hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected); @@ -136,6 +141,12 @@ Hid* hid_alloc(HidTransport transport) { hid_submenu_callback, app); } + submenu_add_item( + app->device_type_submenu, + "Mouse Clicker", + HidSubmenuIndexMouseClicker, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Mouse Jiggler", @@ -209,6 +220,14 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); + // Mouse clicker view + app->hid_mouse_clicker = hid_mouse_clicker_alloc(app); + view_set_previous_callback( + hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewMouseClicker, + hid_mouse_clicker_get_view(app->hid_mouse_clicker)); // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( @@ -244,6 +263,8 @@ void hid_free(Hid* app) { hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); hid_mouse_free(app->hid_mouse); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker); + hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index be9176a28..6fe7d381c 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -24,6 +24,7 @@ #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" #include "views/hid_ytshorts.h" +#include "views/hid_mouse_clicker.h" #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" @@ -46,6 +47,7 @@ struct Hid { HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; + HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; HidTikTok* hid_tiktok; HidYTShorts* hid_ytshorts; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 81e8d6dbe..297fc7bc2 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -5,6 +5,7 @@ typedef enum { HidViewKeyboard, HidViewMedia, HidViewMouse, + HidViewMouseClicker, HidViewMouseJiggler, BtHidViewTikTok, BtHidViewYTShorts, diff --git a/applications/external/hid_app/views/hid_mouse_clicker.c b/applications/external/hid_app/views/hid_mouse_clicker.c new file mode 100644 index 000000000..efaca190a --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.c @@ -0,0 +1,214 @@ +#include "hid_mouse_clicker.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidMouseClicker" +#define DEFAULT_CLICK_RATE 1 +#define MAXIMUM_CLICK_RATE 60 + +struct HidMouseClicker { + View* view; + Hid* hid; + FuriTimer* timer; +}; + +typedef struct { + bool connected; + bool running; + int rate; + HidTransport transport; +} HidMouseClickerModel; + +static void hid_mouse_clicker_start_or_restart_timer(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + if(furi_timer_is_running(hid_mouse_clicker->timer)) { + furi_timer_stop(hid_mouse_clicker->timer); + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + furi_timer_start( + hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate); + }, + true); +} + +static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidMouseClickerModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker"); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->running) { + canvas_set_font(canvas, FontPrimary); + + FuriString* rate_label = furi_string_alloc(); + furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate); + elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label)); + canvas_set_font(canvas, FontSecondary); + furi_string_free(rate_label); + + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking"); + canvas_set_font(canvas, FontSecondary); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + if(model->running) { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + } else { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + } + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); +} + +static void hid_mouse_clicker_timer_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + if(model->running) { + hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + } + }, + false); +} + +static void hid_mouse_clicker_enter_callback(void* context) { + hid_mouse_clicker_start_or_restart_timer(context); +} + +static void hid_mouse_clicker_exit_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + furi_timer_stop(hid_mouse_clicker->timer); +} + +static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + bool consumed = false; + bool rate_changed = false; + + if(event->type != InputTypeRelease) { + return false; + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + switch(event->key) { + case InputKeyOk: + model->running = !model->running; + consumed = true; + break; + case InputKeyUp: + if(model->rate < MAXIMUM_CLICK_RATE) { + model->rate++; + } + rate_changed = true; + consumed = true; + break; + case InputKeyDown: + if(model->rate > 1) { + model->rate--; + } + rate_changed = true; + consumed = true; + break; + default: + consumed = true; + break; + } + }, + true); + + if(rate_changed) { + hid_mouse_clicker_start_or_restart_timer(context); + } + + return consumed; +} + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) { + HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker)); + + hid_mouse_clicker->view = view_alloc(); + view_set_context(hid_mouse_clicker->view, hid_mouse_clicker); + view_allocate_model( + hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel)); + view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback); + view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback); + view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback); + view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback); + + hid_mouse_clicker->hid = hid; + + hid_mouse_clicker->timer = furi_timer_alloc( + hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker); + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + model->transport = hid->transport; + model->rate = DEFAULT_CLICK_RATE; + }, + true); + + return hid_mouse_clicker; +} + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + + furi_timer_stop(hid_mouse_clicker->timer); + furi_timer_free(hid_mouse_clicker->timer); + + view_free(hid_mouse_clicker->view); + + free(hid_mouse_clicker); +} + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + return hid_mouse_clicker->view; +} + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) { + furi_assert(hid_mouse_clicker); + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_mouse_clicker.h b/applications/external/hid_app/views/hid_mouse_clicker.h new file mode 100644 index 000000000..d72847baa --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidMouseClicker HidMouseClicker; + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid); + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker); + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker); + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected); From 28529905662005884e6cbf29416684b41d9d98ac Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:36:28 +0300 Subject: [PATCH 070/216] Add sharp and vizio to ir database --- assets/resources/infrared/assets/tv.ir | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index c55ad267d..bd246f3d6 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 07th Mar, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2, May, 2023 +# Last Checked 2, May, 2023 # name: POWER type: parsed @@ -1899,3 +1899,39 @@ type: parsed protocol: SIRC20 address: 10 01 00 00 command: 33 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655 From 77d63731c93c2d2f7ca34661940c77f0d6e38b3c Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 01:38:19 +0100 Subject: [PATCH 071/216] Loader log arguments passed to app --- applications/services/loader/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 7e40ae54e..808c8e18e 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -43,10 +43,11 @@ static bool furi_assert(loader_instance->application_arguments == NULL); if(arguments && strlen(arguments) > 0) { loader_instance->application_arguments = strdup(arguments); + FURI_LOG_I(TAG, "Starting: %s, args: %s", loader_instance->application->name, arguments); + } else { + FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); } - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); if(mode > FuriHalRtcHeapTrackModeNone) { furi_thread_enable_heap_trace(loader_instance->application_thread); From 311cbf709c4cdfd7f8ca9a558d7f3ec92f777181 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:39:17 +0300 Subject: [PATCH 072/216] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70948b2f5..3a861b0a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ ### New changes * NFC: Temp fix for Detect reader not collecting nonces * Desktop: Temp fix for old backlight bug when locking by holding up arrow +* IR: Add Sharp and Vizio to Universal TV remote * BLE Info: Show version instead of branch * Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) * Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit * Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) * Docs: Update HowToInstall (by @krolchonok | PR #443) +* OFW PR 2627: Add HID mouse auto-clicker (by @rwl4) #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) From 2e162c11311a7e6937e26901fe692fde56a6479c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 04:20:22 +0300 Subject: [PATCH 073/216] Replace QR code with good old link --- assets/slideshow/update_default/frame_01.png | Bin 933 -> 3213 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/slideshow/update_default/frame_01.png b/assets/slideshow/update_default/frame_01.png index 8a1b6585738886eee91d24c415ea17210706e004..ea37077ccd150cf1ac6149567f0cdb3a9ac6eb4b 100644 GIT binary patch literal 3213 zcmcIn32+nV6_$-LhJp#9q@0aLP!7|T{=E-uV_6chTMHW_8oOYcJ^qzdOIo3oPaMa% zKn*l7NiYfE1PUYsN((p{I^hbYfoTl}Cm}YZ7@8p&a|B4HE;mho*^=Wn4)J8Bnpy4c zzwiIv_ul*7(`rS|?5Bne89T&aFbvDgu;-$4H9FD~V$pZO+n1-J)8IfxzHTs>Cx(xh zve##pptU%UD=(Di%o1eHXBHJrg61+`09hLh$ur9WqFe++MhUt-{uI;A1MixQ9wo)} zH0=b=fDIOUGAe>_ZpCbuTu~(RifLx5F}X}Y06rKJjb%QsUl+8g^*RbLJRrS`Zo;Gr(j32qVjzafYHe?x#iq5WoUh3l1=X5C9|4q%ra_A#XuN z6>{yfBEHaFim5OZ3J4ZUX=$mslr(EWw*}{U-U0{(?V`LJ6~!i2)042H}vRhEC_BO?|!|Ydz#BL0%$! z`vlfq9Ezk>n$V^AX@E%uzLM^1}h1$2o z(et<`nt)&nLNTNTU7F^N7Ahx-Vk8JNFiw5i<5#p&eOj1NWCOH|A(&!9RU0pM0HE8{iFBZdA+eV+sxJ;)I3rL%AejF$))bFg-XBw^Q^@q|A<-|xOnZt6 zkurNciolSJDzcJ@K^1x76pFw^iBm9{APHU~c!J=hE?#KAU6YH$=?m}gmaU@62%{%M z0!5GtK?5FRNu0naoKi8Km5@4dk!4k!5mkwaqGbm?sB=VbZ`3d=1tE$wqQ$Wy24tj3 z2q_lh30%c!o}pEdBuR$kO-4l)R4wQekxo25(G4vDzuRQ|nvG5KYC)%_pq!Jv*E4Ol zoS>$9yy$_R`&7Cy(_v$9o?$S;jE7~9XrOR2JUXgzd8Co%!bOoQugBP>PC=BzO_5@f z!)kzvDYES8BhCE_s2jGl5F*e=sHEFW*VIs{7=%_gD#>@M(DH5Mb+P2p)OnTWc^WVn zOA$DxDwKk8G7m6bCKwi1SU^EF8v6f*dL*rKq3Cx*G+`~K?;lM6XDkJi|(H4ruN;KBqIVG@;t_n6lzC6k>OsKFXaS3q(X3$N$9uo#IZWr~5Qwb8VI3IgOHr(!D35(-oZ0?4qxSdz-p1j+Ci$lfC?QRjj-GmPhNP%d*!`IVy735_&%f zU-rD1pqrjo8|X*f7DO*DsfS{%2EzbLrrqi)tG~XX@x{Lw6Vl|37w&yE^W*v3$s3L5 zh7Pm?d{_R39UCP_jJ07}$HBO&^9M)Wxw$l^e((TpWPD)q(0^o&KC&KElcK?W)Nrcz zgOgYPSpEFk4{nXQwW#RySE(anPHoG7;J9>&JZ`mDlP`T%9oyM?Zbd>str?&8@X+O~ z><1e@{ncbs6wRDFuzCKE9B~|J9p$Rs7ywJ>jL4~9^aLAHym2Qtj?0#7WA;6}CZSLw z)6V6e+g-PC_wdA`(fOmQR|zwf#iq1d*Xs2VuN-|i_g+&?$F*IDYOQT&*DhbbPA!?-s>8_ ze%|t=>fm?IS5sT#E0|K^@| z_wdDI5{JW*=e+GXol`2Sell)o#qXPMWM4`keAj3%xN&jt*|>A7tA9CsLKP@JGT^T( zy<0p}bA^MmNbPpsCyryUmDlZmzm$uee!tasw>9rW{1@>{9_(9_+IGS_`^eR_i_KR$ z+HH$%)a*l^yA_9CJMDIk{@YtW|LFYvEcwcrqboPGzP|TV#iUmg+n2N)9*oavj&a<0 zSas3==hGc8=~c-;zJ0%7oqPNC*w}k}cdbfTR=r^2o_}uHP25h(BbR;p#D-_bwEf`f zbpEnu?)0@+(uxvVD=T*_ozWDN^WwbC1q11~R?^p7mi+eRY&tu6TaJI>in#Koro>t7 zu4Ut2D6F~u_tot;t6Se|U+kN=HUF`Ooj)5gbTaPoM?gwB>7 zUpnv9FI2zWI&Ac@=8Bj9?b1#6>Qj^5pZsp}Z?f74{p;|njZ<87L!xtU;+;TpvtjGF yQ4<#X?(KN^g}K2!*L?l~e?I=ejhIHR%5a!=JyZ0-)}7%$44IDE_CKXRQ}Z9Je{J0W delta 922 zcmV;L17-Y;8Kno18Gi-<007d~e}4b~00DDSM?wIu&K&6g00Uo1L_t(|ob8iBe`WTIE%GqFHinSeN1D{8gnErJ{z^)%wO&bBzMd8!d6raw;G_ZsClw$#sQ|%A z1qexbc^7;ek2sM5Y`9a z;FQavbV!(YUGfFAo`*100IxlkTglq0-|2fkr5EOTXMa6s32OnYj;MA#RRXILuTp+f zKfr9Egd5MzYwasQ~ffSQ&bHhIHumsl_D^fSAGFdoHP>m1ouJh(P86 zf@A6j(0cFMW(#Q?nwEW2zThd+0tBawo)P4|w`${it;I-Fkw~;yjb%gc-Jb1fxaPa}? z_}OY77Y#^qadIR)p?!c^W>)|1JCHa`nLuk_0Dm2au2i%ZVDV8b-oD3$-)Wsj|6^zi zpt+D9EB2|ai3@eFYwY;fCg!^~C-I1FiWE9|e!Jl?CXWQzQJ|hUdvqxJi zm^uDQ7oS7p*MzeG9v7`vzuVbMDZhWc Date: Tue, 2 May 2023 03:39:50 +0100 Subject: [PATCH 074/216] Add favorite timeout setting --- .../main/archive/helpers/favorite_timeout.c | 34 +++++++++++++++++++ .../main/archive/helpers/favorite_timeout.h | 16 +++++++++ .../archive/scenes/archive_scene_browser.c | 14 +++++--- applications/main/bad_kb/bad_kb_app.c | 6 ++-- applications/main/fap_loader/fap_loader_app.c | 4 ++- applications/main/ibutton/ibutton.c | 10 ++++-- applications/main/infrared/infrared.c | 4 ++- applications/main/lfrfid/lfrfid.c | 11 ++++-- applications/main/nfc/nfc.c | 13 ++++--- applications/main/subghz/subghz.c | 4 ++- .../xtreme_app_scene_interface_common.c | 17 ++++++++++ applications/system/updater/application.fam | 2 ++ applications/system/updater/updater.c | 8 ++--- lib/xtreme/settings.c | 4 +++ lib/xtreme/xtreme.h | 1 + 15 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 applications/main/archive/helpers/favorite_timeout.c create mode 100644 applications/main/archive/helpers/favorite_timeout.h diff --git a/applications/main/archive/helpers/favorite_timeout.c b/applications/main/archive/helpers/favorite_timeout.c new file mode 100644 index 000000000..703f6c796 --- /dev/null +++ b/applications/main/archive/helpers/favorite_timeout.c @@ -0,0 +1,34 @@ +#include "favorite_timeout.h" +#include + +bool process_favorite_launch(char** args) { + if(*args && strlen(*args) > 4 && strncmp(*args, "fav/", 4) == 0) { + *args += 3; + return true; + } + return false; +} + +void favorite_timeout_callback(void* _ctx) { + FavoriteTImeoutCtx* ctx = _ctx; + while(scene_manager_handle_back_event(ctx->scene_manager)); + view_dispatcher_stop(ctx->view_dispatcher); +} + +void favorite_timeout_run(ViewDispatcher* view_dispatcher, SceneManager* scene_manager) { + int32_t timeout = XTREME_SETTINGS()->favorite_timeout; + if(timeout == 0) { + view_dispatcher_run(view_dispatcher); + return; + } + + FavoriteTImeoutCtx ctx = { + .view_dispatcher = view_dispatcher, + .scene_manager = scene_manager + }; + FuriTimer* timer = furi_timer_alloc(favorite_timeout_callback, FuriTimerTypeOnce, &ctx); + furi_timer_start(timer, timeout * furi_kernel_get_tick_frequency()); + view_dispatcher_run(view_dispatcher); + furi_timer_stop(timer); + furi_timer_free(timer); +} diff --git a/applications/main/archive/helpers/favorite_timeout.h b/applications/main/archive/helpers/favorite_timeout.h new file mode 100644 index 000000000..aded05708 --- /dev/null +++ b/applications/main/archive/helpers/favorite_timeout.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +bool process_favorite_launch(char** p); + +typedef struct { + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; +} FavoriteTImeoutCtx; + +void favorite_timeout_callback(void* _ctx); + +void favorite_timeout_run(ViewDispatcher* view_dispatcher, SceneManager* scene_manager); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index 3154fbec6..0f4d48db1 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -36,7 +36,7 @@ static void archive_loader_callback(const void* message, void* context) { } } -static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) { +static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) { UNUSED(browser); Loader* loader = furi_record_open(RECORD_LOADER); @@ -48,8 +48,14 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec } status = loader_start(loader, flipper_app_name[selected->type], param); } else { - status = loader_start( - loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); + if(favorites) { + const char* str = furi_string_get_cstr(selected->path); + char arg[strlen(str) + 4]; + snprintf(arg, sizeof(arg), "fav%s", str); + status = loader_start(loader, flipper_app_name[selected->type], arg); + } else { + status = loader_start(loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); + } } if(status != LoaderStatusOk) { @@ -113,7 +119,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { archive_show_file_menu(browser, false); archive_enter_dir(browser, selected->path); } else if(archive_is_known_app(selected->type)) { - archive_run_in_app(browser, selected); + archive_run_in_app(browser, selected, favorites); archive_show_file_menu(browser, false); } consumed = true; diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c index 94a74aa92..e8b29b837 100644 --- a/applications/main/bad_kb/bad_kb_app.c +++ b/applications/main/bad_kb/bad_kb_app.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -204,6 +205,7 @@ BadKbApp* bad_kb_app_alloc(char* arg) { app->file_path = furi_string_alloc(); app->keyboard_layout = furi_string_alloc(); + process_favorite_launch(&arg); if(arg && strlen(arg)) { furi_string_set(app->file_path, arg); } @@ -336,8 +338,8 @@ void bad_kb_app_free(BadKbApp* app) { free(app); } -int32_t bad_kb_app(void* p) { - BadKbApp* bad_kb_app = bad_kb_app_alloc((char*)p); +int32_t bad_kb_app(char* p) { + BadKbApp* bad_kb_app = bad_kb_app_alloc(p); view_dispatcher_run(bad_kb_app->view_dispatcher); diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index b313d67ad..87eafaecd 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -12,6 +12,7 @@ #include #include #include +#include #define TAG "FapLoader" @@ -241,8 +242,9 @@ static void fap_loader_free(FapLoader* loader) { free(loader); } -int32_t fap_loader_app(void* p) { +int32_t fap_loader_app(char* p) { FapLoader* loader; + process_favorite_launch(&p); if(p) { loader = fap_loader_alloc((const char*)p); view_dispatcher_switch_to_view(loader->view_dispatcher, 0); diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index 79999adb2..3fea2d2f6 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -2,6 +2,7 @@ #include #include +#include #define TAG "iButtonApp" @@ -258,13 +259,14 @@ void ibutton_widget_callback(GuiButtonType result, InputType type, void* context } } -int32_t ibutton_app(void* arg) { +int32_t ibutton_app(char* arg) { iButton* ibutton = ibutton_alloc(); ibutton_make_app_folder(ibutton); bool key_loaded = false; + bool is_favorite = process_favorite_launch(&arg); if((arg != NULL) && (strlen(arg) != 0)) { if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) { FURI_LOG_D(TAG, "Running in RPC mode"); @@ -295,7 +297,11 @@ int32_t ibutton_app(void* arg) { } } - view_dispatcher_run(ibutton->view_dispatcher); + if(is_favorite) { + favorite_timeout_run(ibutton->view_dispatcher, ibutton->scene_manager); + } else { + view_dispatcher_run(ibutton->view_dispatcher); + } if(ibutton->rpc) { rpc_system_app_set_callback(ibutton->rpc, NULL, NULL); diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index b8195941b..0abd6c709 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -2,6 +2,7 @@ #include #include +#include #define INFRARED_TX_MIN_INTERVAL_MS 50U @@ -435,7 +436,7 @@ void infrared_popup_closed_callback(void* context) { infrared->view_dispatcher, InfraredCustomEventTypePopupClosed); } -int32_t infrared_app(void* p) { +int32_t infrared_app(char* p) { Infrared* infrared = infrared_alloc(); infrared_make_app_folder(infrared); @@ -443,6 +444,7 @@ int32_t infrared_app(void* p) { bool is_remote_loaded = false; bool is_rpc_mode = false; + process_favorite_launch(&p); if(p && strlen(p)) { uint32_t rpc_ctx = 0; if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index a2bcdcf52..eacb05614 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -1,5 +1,6 @@ #include "lfrfid_i.h" #include +#include static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -168,12 +169,12 @@ static void lfrfid_free(LfRfid* lfrfid) { free(lfrfid); } -int32_t lfrfid_app(void* p) { +int32_t lfrfid_app(char* args) { LfRfid* app = lfrfid_alloc(); - char* args = p; lfrfid_make_app_folder(app); + bool is_favorite = process_favorite_launch(&args); if(args && strlen(args)) { uint32_t rpc_ctx_ptr = 0; if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) { @@ -199,7 +200,11 @@ int32_t lfrfid_app(void* p) { scene_manager_next_scene(app->scene_manager, LfRfidSceneStart); } - view_dispatcher_run(app->view_dispatcher); + if(is_favorite) { + favorite_timeout_run(app->view_dispatcher, app->scene_manager); + } else { + view_dispatcher_run(app->view_dispatcher); + } lfrfid_free(app); diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index f68b7f2f2..9ff82eaa4 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -1,6 +1,7 @@ #include "nfc_i.h" #include #include +#include bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -263,14 +264,14 @@ static bool nfc_is_hal_ready() { } } -int32_t nfc_app(void* p) { +int32_t nfc_app(char* p) { if(!nfc_is_hal_ready()) return 0; Nfc* nfc = nfc_alloc(); - char* args = p; // Check argument and run corresponding scene - if(args && strlen(args)) { + bool is_favorite = process_favorite_launch(&p); + if(p && strlen(p)) { nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); uint32_t rpc_ctx = 0; if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { @@ -311,7 +312,11 @@ int32_t nfc_app(void* p) { scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); } - view_dispatcher_run(nfc->view_dispatcher); + if(is_favorite) { + favorite_timeout_run(nfc->view_dispatcher, nfc->scene_manager); + } else { + view_dispatcher_run(nfc->view_dispatcher); + } nfc_free(nfc); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 47da7ae40..a092fa6f6 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -4,6 +4,7 @@ #include #include "subghz_i.h" #include +#include #define TAG "SubGhzApp" @@ -423,7 +424,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { free(subghz); } -int32_t subghz_app(void* p) { +int32_t subghz_app(char* p) { bool alloc_for_tx; if(p && strlen(p)) { alloc_for_tx = true; @@ -455,6 +456,7 @@ int32_t subghz_app(void* p) { furi_hal_subghz_init_radio_type(SubGhzRadioInternal); } // Check argument and run corresponding scene + process_favorite_launch(&p); if(p && strlen(p)) { uint32_t rpc_ctx = 0; diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c index 259d8a260..08b7425f6 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c @@ -37,6 +37,16 @@ static void xtreme_app_scene_interface_common_left_handed_changed(VariableItem* } } +static void xtreme_app_scene_interface_common_favorite_timeout_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint32_t value = variable_item_get_current_value_index(item); + char text[6]; + snprintf(text, sizeof(text), "%lu S", value); + variable_item_set_current_value_text(item, value ? text : "OFF"); + XTREME_SETTINGS()->favorite_timeout = value; + app->save_settings = true; +} + void xtreme_app_scene_interface_common_on_enter(void* context) { XtremeApp* app = context; XtremeSettings* xtreme_settings = XTREME_SETTINGS(); @@ -67,6 +77,13 @@ void xtreme_app_scene_interface_common_on_enter(void* context) { variable_item_set_current_value_index(item, value); variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + item = variable_item_list_add( + var_item_list, "Favorite Timeout", 61, xtreme_app_scene_interface_common_favorite_timeout_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->favorite_timeout); + char text[4]; + snprintf(text, sizeof(text), "%lu S", xtreme_settings->favorite_timeout); + variable_item_set_current_value_text(item, xtreme_settings->favorite_timeout ? text : "OFF"); + variable_item_list_set_enter_callback( var_item_list, xtreme_app_scene_interface_common_var_item_list_callback, app); diff --git a/applications/system/updater/application.fam b/applications/system/updater/application.fam index ae6914eb7..4d62c1d48 100644 --- a/applications/system/updater/application.fam +++ b/applications/system/updater/application.fam @@ -7,6 +7,7 @@ App( "gui", "storage", "rgb_backlight", + "archive", ], conflicts=["desktop"], entry_point="updater_srv", @@ -23,6 +24,7 @@ App( "gui", "storage", "bt", + "archive", ], conflicts=["updater"], provides=["updater_start"], diff --git a/applications/system/updater/updater.c b/applications/system/updater/updater.c index e749f3ce6..e0b723270 100644 --- a/applications/system/updater/updater.c +++ b/applications/system/updater/updater.c @@ -7,6 +7,7 @@ #include #include #include +#include static bool updater_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -34,6 +35,7 @@ static void Updater* updater_alloc(const char* arg) { Updater* updater = malloc(sizeof(Updater)); + process_favorite_launch(&arg); if(arg && strlen(arg)) { updater->startup_arg = furi_string_alloc_set(arg); furi_string_replace(updater->startup_arg, ANY_PATH(""), EXT_PATH("")); @@ -118,10 +120,8 @@ void updater_free(Updater* updater) { free(updater); } -int32_t updater_srv(void* p) { - const char* cfgpath = p; - - Updater* updater = updater_alloc(cfgpath); +int32_t updater_srv(char* p) { + Updater* updater = updater_alloc(p); view_dispatcher_run(updater->view_dispatcher); updater_free(updater); diff --git a/lib/xtreme/settings.c b/lib/xtreme/settings.c index 1cafa6f59..fe6520808 100644 --- a/lib/xtreme/settings.c +++ b/lib/xtreme/settings.c @@ -24,6 +24,7 @@ XtremeSettings xtreme_settings = { .bar_background = false, // OFF .sort_dirs_first = true, // ON .dark_mode = false, // OFF + .favorite_timeout = 0, // OFF .bad_bt = false, // USB .bad_bt_remember = false, // OFF .butthurt_timer = 43200, // 12 H @@ -75,6 +76,8 @@ void XTREME_SETTINGS_LOAD() { flipper_format_rewind(file); flipper_format_read_bool(file, "dark_mode", &x->dark_mode, 1); flipper_format_rewind(file); + flipper_format_read_uint32(file, "favorite_timeout", &x->favorite_timeout, 1); + flipper_format_rewind(file); flipper_format_read_bool(file, "bad_bt", &x->bad_bt, 1); flipper_format_rewind(file); flipper_format_read_bool(file, "bad_bt_remember", &x->bad_bt_remember, 1); @@ -112,6 +115,7 @@ void XTREME_SETTINGS_SAVE() { flipper_format_write_bool(file, "bar_background", &x->bar_background, 1); flipper_format_write_bool(file, "sort_dirs_first", &x->sort_dirs_first, 1); flipper_format_write_bool(file, "dark_mode", &x->dark_mode, 1); + flipper_format_write_uint32(file, "favorite_timeout", &x->favorite_timeout, 1); flipper_format_write_bool(file, "bad_bt", &x->bad_bt, 1); flipper_format_write_bool(file, "bad_bt_remember", &x->bad_bt_remember, 1); flipper_format_write_int32(file, "butthurt_timer", &x->butthurt_timer, 1); diff --git a/lib/xtreme/xtreme.h b/lib/xtreme/xtreme.h index 63f457c27..54c208ae7 100644 --- a/lib/xtreme/xtreme.h +++ b/lib/xtreme/xtreme.h @@ -31,6 +31,7 @@ typedef struct { bool bar_background; bool sort_dirs_first; bool dark_mode; + uint32_t favorite_timeout; bool bad_bt; bool bad_bt_remember; int32_t butthurt_timer; From 8a5782ab9eb4cacde003886148bf153145bef448 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 03:44:29 +0100 Subject: [PATCH 075/216] Format --- applications/main/archive/helpers/favorite_timeout.c | 8 +++----- applications/main/archive/scenes/archive_scene_browser.c | 7 ++++--- .../xtreme_app/scenes/xtreme_app_scene_interface_common.c | 6 +++++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/applications/main/archive/helpers/favorite_timeout.c b/applications/main/archive/helpers/favorite_timeout.c index 703f6c796..b46057d82 100644 --- a/applications/main/archive/helpers/favorite_timeout.c +++ b/applications/main/archive/helpers/favorite_timeout.c @@ -11,7 +11,8 @@ bool process_favorite_launch(char** args) { void favorite_timeout_callback(void* _ctx) { FavoriteTImeoutCtx* ctx = _ctx; - while(scene_manager_handle_back_event(ctx->scene_manager)); + while(scene_manager_handle_back_event(ctx->scene_manager)) + ; view_dispatcher_stop(ctx->view_dispatcher); } @@ -22,10 +23,7 @@ void favorite_timeout_run(ViewDispatcher* view_dispatcher, SceneManager* scene_m return; } - FavoriteTImeoutCtx ctx = { - .view_dispatcher = view_dispatcher, - .scene_manager = scene_manager - }; + FavoriteTImeoutCtx ctx = {.view_dispatcher = view_dispatcher, .scene_manager = scene_manager}; FuriTimer* timer = furi_timer_alloc(favorite_timeout_callback, FuriTimerTypeOnce, &ctx); furi_timer_start(timer, timeout * furi_kernel_get_tick_frequency()); view_dispatcher_run(view_dispatcher); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index 0f4d48db1..f0884ab73 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -36,7 +36,8 @@ static void archive_loader_callback(const void* message, void* context) { } } -static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) { +static void + archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) { UNUSED(browser); Loader* loader = furi_record_open(RECORD_LOADER); @@ -48,13 +49,13 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec } status = loader_start(loader, flipper_app_name[selected->type], param); } else { + const char* str = furi_string_get_cstr(selected->path); if(favorites) { - const char* str = furi_string_get_cstr(selected->path); char arg[strlen(str) + 4]; snprintf(arg, sizeof(arg), "fav%s", str); status = loader_start(loader, flipper_app_name[selected->type], arg); } else { - status = loader_start(loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); + status = loader_start(loader, flipper_app_name[selected->type], str); } } diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c index 08b7425f6..54b0241d9 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_common.c @@ -78,7 +78,11 @@ void xtreme_app_scene_interface_common_on_enter(void* context) { variable_item_set_current_value_text(item, value ? "ON" : "OFF"); item = variable_item_list_add( - var_item_list, "Favorite Timeout", 61, xtreme_app_scene_interface_common_favorite_timeout_changed, app); + var_item_list, + "Favorite Timeout", + 61, + xtreme_app_scene_interface_common_favorite_timeout_changed, + app); variable_item_set_current_value_index(item, xtreme_settings->favorite_timeout); char text[4]; snprintf(text, sizeof(text), "%lu S", xtreme_settings->favorite_timeout); From 602459869571e1aeca25eb9dfc8481eb8d07271b Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 03:44:38 +0100 Subject: [PATCH 076/216] Fix build --- applications/system/updater/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/updater/updater.c b/applications/system/updater/updater.c index e0b723270..59af8a3b0 100644 --- a/applications/system/updater/updater.c +++ b/applications/system/updater/updater.c @@ -33,7 +33,7 @@ static void updater_main_model_set_state(main_view, message, progress, failed); } -Updater* updater_alloc(const char* arg) { +Updater* updater_alloc(char* arg) { Updater* updater = malloc(sizeof(Updater)); process_favorite_launch(&arg); if(arg && strlen(arg)) { From 706ce56a48b18dac3f924cf8d50a87c4bea9ecb7 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 03:48:00 +0100 Subject: [PATCH 077/216] Actually fix build --- applications/system/updater/updater_i.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/updater/updater_i.h b/applications/system/updater/updater_i.h index 4e3c704d2..4940eb60e 100644 --- a/applications/system/updater/updater_i.h +++ b/applications/system/updater/updater_i.h @@ -52,7 +52,7 @@ typedef struct { int32_t idle_ticks; } Updater; -Updater* updater_alloc(const char* arg); +Updater* updater_alloc(char* arg); void updater_free(Updater* updater); From 84c1cac63c813a0f41ebf439ad99513d73e72b3e Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 05:45:19 +0100 Subject: [PATCH 078/216] Format --- applications/external/bomberduck/application.fam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/bomberduck/application.fam b/applications/external/bomberduck/application.fam index 2f8246af9..d2ee5564b 100644 --- a/applications/external/bomberduck/application.fam +++ b/applications/external/bomberduck/application.fam @@ -8,7 +8,7 @@ App( ], stack_size=1 * 1024, order=90, - fap_icon="bomb.png", + fap_icon="bomb.png", fap_category="Games", fap_icon_assets="assets", ) From c0cf699edeac7411649bce2c5afae95e185ba912 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 12:32:45 +0100 Subject: [PATCH 079/216] Support subghz raw in favorite timeout setting --- .../subghz/scenes/subghz_scene_read_raw.c | 20 ++++++++++++++++ applications/main/subghz/subghz.c | 5 +++- .../main/subghz/views/subghz_read_raw.c | 22 ----------------- .../main/subghz/views/subghz_read_raw.h | 24 +++++++++++++++++-- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 0c692e000..2638d2089 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -122,6 +122,19 @@ void subghz_scene_read_raw_on_enter(void* context) { //set filter RAW feed subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); + + // Start sending immediately with favorites + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW)) { + with_view_model( + subghz->subghz_read_raw->view, + SubGhzReadRAWModel * model, + { + scene_manager_handle_custom_event( + subghz->scene_manager, SubGhzCustomEventViewReadRAWSendStart); + model->status = SubGhzReadRAWStatusTXRepeat; + }, + true); + } } bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { @@ -278,6 +291,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); } subghz_read_raw_stop_send(subghz->subghz_read_raw); + + // Exit / stop with favorites + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW)) { + while(scene_manager_handle_back_event(subghz->scene_manager)) + ; + view_dispatcher_stop(subghz->view_dispatcher); + } consumed = true; break; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index a092fa6f6..906b8e074 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -5,6 +5,7 @@ #include "subghz_i.h" #include #include +#include #define TAG "SubGhzApp" @@ -456,7 +457,7 @@ int32_t subghz_app(char* p) { furi_hal_subghz_init_radio_type(SubGhzRadioInternal); } // Check argument and run corresponding scene - process_favorite_launch(&p); + bool is_favorite = process_favorite_launch(&p) && XTREME_SETTINGS()->favorite_timeout; if(p && strlen(p)) { uint32_t rpc_ctx = 0; @@ -476,6 +477,8 @@ int32_t subghz_app(char* p) { if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { //Load Raw TX subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, is_favorite); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index fcc077efa..7676c527d 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -11,28 +11,6 @@ #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100 #define TAG "SubGhzReadRAW" -struct SubGhzReadRAW { - View* view; - SubGhzReadRAWCallback callback; - void* context; -}; - -typedef struct { - FuriString* frequency_str; - FuriString* preset_str; - FuriString* sample_write; - FuriString* file_name; - uint8_t* rssi_history; - uint8_t rssi_current; - bool rssi_history_end; - uint8_t ind_write; - uint8_t ind_sin; - SubGhzReadRAWStatus status; - bool raw_send_only; - float raw_threshold_rssi; - bool not_showing_samples; -} SubGhzReadRAWModel; - void subghz_read_raw_set_callback( SubGhzReadRAW* subghz_read_raw, SubGhzReadRAWCallback callback, diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 9d63870d5..f9a56ca04 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -5,10 +5,14 @@ #define SUBGHZ_RAW_THRESHOLD_MIN -90.0f -typedef struct SubGhzReadRAW SubGhzReadRAW; - typedef void (*SubGhzReadRAWCallback)(SubGhzCustomEvent event, void* context); +typedef struct { + View* view; + SubGhzReadRAWCallback callback; + void* context; +} SubGhzReadRAW; + typedef enum { SubGhzReadRAWStatusStart, SubGhzReadRAWStatusIDLE, @@ -22,6 +26,22 @@ typedef enum { SubGhzReadRAWStatusSaveKey, } SubGhzReadRAWStatus; +typedef struct { + FuriString* frequency_str; + FuriString* preset_str; + FuriString* sample_write; + FuriString* file_name; + uint8_t* rssi_history; + uint8_t rssi_current; + bool rssi_history_end; + uint8_t ind_write; + uint8_t ind_sin; + SubGhzReadRAWStatus status; + bool raw_send_only; + float raw_threshold_rssi; + bool not_showing_samples; +} SubGhzReadRAWModel; + void subghz_read_raw_set_callback( SubGhzReadRAW* subghz_read_raw, SubGhzReadRAWCallback callback, From 45406cf579e7f31bb062b07f32341c1eff9b2b07 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 12:33:08 +0100 Subject: [PATCH 080/216] Remove USB HID Autofire (now in USB / BT Remotes) --- .../external/usb_hid_autofire/CHANGELOG.md | 13 - .../external/usb_hid_autofire/LICENSE | 674 ------------------ .../external/usb_hid_autofire/application.fam | 13 - .../external/usb_hid_autofire/tools.c | 50 -- .../external/usb_hid_autofire/tools.h | 7 - .../usb_hid_autofire/usb_hid_autofire.c | 127 ---- .../usb_hid_autofire/usb_hid_autofire.kra | Bin 50949 -> 0 bytes .../usb_hid_autofire/usb_hid_autofire.png | Bin 641 -> 0 bytes .../usb_hid_autofire/usb_hid_autofire.svg | 75 -- .../external/usb_hid_autofire/version.h | 1 - 10 files changed, 960 deletions(-) delete mode 100644 applications/external/usb_hid_autofire/CHANGELOG.md delete mode 100644 applications/external/usb_hid_autofire/LICENSE delete mode 100644 applications/external/usb_hid_autofire/application.fam delete mode 100644 applications/external/usb_hid_autofire/tools.c delete mode 100644 applications/external/usb_hid_autofire/tools.h delete mode 100644 applications/external/usb_hid_autofire/usb_hid_autofire.c delete mode 100644 applications/external/usb_hid_autofire/usb_hid_autofire.kra delete mode 100644 applications/external/usb_hid_autofire/usb_hid_autofire.png delete mode 100644 applications/external/usb_hid_autofire/usb_hid_autofire.svg delete mode 100644 applications/external/usb_hid_autofire/version.h diff --git a/applications/external/usb_hid_autofire/CHANGELOG.md b/applications/external/usb_hid_autofire/CHANGELOG.md deleted file mode 100644 index d0924edd3..000000000 --- a/applications/external/usb_hid_autofire/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -# Changelog - -## 0.4 -- Show active/inactive state in primary font (bold) - -## 0.3 -- Add a delay between key-presses (with left/right buttons) - -## 0.2 -- Update icon - -## 0.1 -- Initial release of the USB HID Autofire application diff --git a/applications/external/usb_hid_autofire/LICENSE b/applications/external/usb_hid_autofire/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/applications/external/usb_hid_autofire/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/applications/external/usb_hid_autofire/application.fam b/applications/external/usb_hid_autofire/application.fam deleted file mode 100644 index 9e7b9378c..000000000 --- a/applications/external/usb_hid_autofire/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="usb_hid_autofire", - name="USB HID Autofire", - apptype=FlipperAppType.EXTERNAL, - entry_point="usb_hid_autofire_app", - cdefines=["APP_USB_HID_AUTOFIRE"], - requires=[ - "gui", - ], - stack_size=1 * 1024, - fap_icon="usb_hid_autofire.png", - fap_category="Misc", -) diff --git a/applications/external/usb_hid_autofire/tools.c b/applications/external/usb_hid_autofire/tools.c deleted file mode 100644 index 566d00564..000000000 --- a/applications/external/usb_hid_autofire/tools.c +++ /dev/null @@ -1,50 +0,0 @@ -// -// Tools for USB HID Autofire -// - -void strrev(char* arr, int start, int end) { - char temp; - - if(start >= end) return; - - temp = *(arr + start); - *(arr + start) = *(arr + end); - *(arr + end) = temp; - - start++; - end--; - strrev(arr, start, end); -} - -char* itoa(int number, char* arr, int base) { - int i = 0, r, negative = 0; - - if(number == 0) { - arr[i] = '0'; - arr[i + 1] = '\0'; - return arr; - } - - if(number < 0 && base == 10) { - number *= -1; - negative = 1; - } - - while(number != 0) { - r = number % base; - arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0'; - i++; - number /= base; - } - - if(negative) { - arr[i] = '-'; - i++; - } - - strrev(arr, 0, i - 1); - - arr[i] = '\0'; - - return arr; -} diff --git a/applications/external/usb_hid_autofire/tools.h b/applications/external/usb_hid_autofire/tools.h deleted file mode 100644 index 7e5226514..000000000 --- a/applications/external/usb_hid_autofire/tools.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef FLIPPERZERO_FIRMWARE_TOOLS_H -#define FLIPPERZERO_FIRMWARE_TOOLS_H - -void strrev(char* arr, int start, int end); -char* itoa(int number, char* arr, int base); - -#endif //FLIPPERZERO_FIRMWARE_TOOLS_H diff --git a/applications/external/usb_hid_autofire/usb_hid_autofire.c b/applications/external/usb_hid_autofire/usb_hid_autofire.c deleted file mode 100644 index cf8077ae7..000000000 --- a/applications/external/usb_hid_autofire/usb_hid_autofire.c +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#include -#include -#include -#include "version.h" -#include "tools.h" - -// Uncomment to be able to make a screenshot -//#define USB_HID_AUTOFIRE_SCREENSHOT - -typedef enum { - EventTypeInput, -} EventType; - -typedef struct { - union { - InputEvent input; - }; - EventType type; -} UsbMouseEvent; - -bool btn_left_autofire = false; -uint32_t autofire_delay = 10; - -static void usb_hid_autofire_render_callback(Canvas* canvas, void* ctx) { - UNUSED(ctx); - char autofire_delay_str[12]; - //std::string pi = "pi is " + std::to_string(3.1415926); - itoa(autofire_delay, autofire_delay_str, 10); - //sprintf(autofire_delay_str, "%lu", autofire_delay); - - canvas_clear(canvas); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 0, 10, "USB HID Autofire"); - canvas_draw_str(canvas, 0, 34, btn_left_autofire ? "" : ""); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 90, 10, "v"); - canvas_draw_str(canvas, 96, 10, VERSION); - canvas_draw_str(canvas, 0, 22, "Press [ok] for auto left clicking"); - canvas_draw_str(canvas, 0, 46, "delay [ms]:"); - canvas_draw_str(canvas, 50, 46, autofire_delay_str); - canvas_draw_str(canvas, 0, 63, "Press [back] to exit"); -} - -static void usb_hid_autofire_input_callback(InputEvent* input_event, void* ctx) { - FuriMessageQueue* event_queue = ctx; - - UsbMouseEvent event; - event.type = EventTypeInput; - event.input = *input_event; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -int32_t usb_hid_autofire_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(UsbMouseEvent)); - furi_check(event_queue); - ViewPort* view_port = view_port_alloc(); - - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); -#ifndef USB_HID_AUTOFIRE_SCREENSHOT - furi_hal_usb_unlock(); - furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); -#endif - - view_port_draw_callback_set(view_port, usb_hid_autofire_render_callback, NULL); - view_port_input_callback_set(view_port, usb_hid_autofire_input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - UsbMouseEvent event; - while(1) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 50); - - if(event_status == FuriStatusOk) { - if(event.type == EventTypeInput) { - if(event.input.key == InputKeyBack) { - break; - } - - if(event.input.type != InputTypeRelease) { - continue; - } - - switch(event.input.key) { - case InputKeyOk: - btn_left_autofire = !btn_left_autofire; - break; - case InputKeyLeft: - if(autofire_delay > 0) { - autofire_delay -= 10; - } - break; - case InputKeyRight: - autofire_delay += 10; - break; - default: - break; - } - } - } - - if(btn_left_autofire) { - furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); - // TODO: Don't wait, but use the timer directly to just don't send the release event (see furi_hal_cortex_delay_us) - furi_delay_us(autofire_delay * 500); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); - furi_delay_us(autofire_delay * 500); - } - - view_port_update(view_port); - } - - furi_hal_usb_set_config(usb_mode_prev, NULL); - - // remove & free all stuff created by app - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); - - return 0; -} diff --git a/applications/external/usb_hid_autofire/usb_hid_autofire.kra b/applications/external/usb_hid_autofire/usb_hid_autofire.kra deleted file mode 100644 index 21d41654829152f856c81b842ab51642a698c97b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50949 zcmV)WK(4<~O9KQ7000000E>ikRiW?$rxO4G022TJ00;m80Bvb)WpsIPWnpk|Y-wX* zbZKvHFL*6$a%ps7P)h>@6aWAK2mp(Ob5#@CAd^@F003_X000XB003=aX>Me1V=j1Y zY^_yYZ`(E$eb2Ap_>vA7EmN{AtFTfyaT*kDH)Bfz^pT=yn>8g0B%Q=4`rmg+$+4G@ zb`KR`i&wl~=iDP|`tG4t=uQ|bbyHwE7-A$Et}EHB3Vd_@o=ot&vy^S>^xzbq~h z+|lCZ{L_aEbV{P=3|LrjO?y)?BVfg9Dr2PX;a{jA@1x1O+S2| zU0tFbF#<}_A^6m?76oQ)t0ZR*VxtGLF;Jy7dMOp`*}t#OiBL+A+n89hDxKj2$vH-q zu-wSjg^C!hgUhG1_irRp4)vBw5Bo#>prx6EaHpnB-iH3D3qf%ju-#<@h_)U9+YUYN^=D z`fj{P0bWWchbtzgQlTT#ab(%hDV_*;dU)-wM;fH^Z;!ac+^8utQ0D^ z?!tdxPiemCYf`u{f?%Lr$)>BK8(`0FWD|lk@FE=~h|?4!AGv-*lI$lzqmuX2D z6BQXPD_B(tBYB)wrI_%^lCtm5Ucx7ndZPNkY|mvNcDgY7EA$G)oin~!8NF?)Zc^cY z&KxUn1lMd<6n*@a(j`+fYo&FpaklgSN7k(pM^Q8z|FQphhPvPdQ^Gl6I}46Vy)}Gq zvPRb7=Z2@2mn(yWq9_&vD!2Ns;}&g0&lZ;b%~ zUW4a8@$iMb)9ARJX%xOV@QI7y8+Uf{FHlPZ1QY-O00;n!gmYCCOO%3}0RRAL0{{RJ z0001FZ)0_BWo~q7Zf0*Tcx`Nrl0j4BAQ*=4{S`5no(Lt5?%JU^+SHjHcXmCbhaJZQ zB{ZT0IzTq|-wQEGo9e++-aOy?@$mxq`mK`De{QVMY7wJk7Drq$T?kb!;&pxpe#X~i zg3q$Q%lzNNDk?OqE3O<6YOAA%_3iIp%V-K9yw6q;W_fnvKna3y^=BGQpPk#yA#9o^ zVN^;{8k%TRh8{TT0lp_GTru@?$BX&BD!Yiky;4jj5vChmJ1-*agp-_L`0)*-;FcM& zb3VN1$A6(}>&**i&R2RBDBW0RXuxNW%j_n{V5IO{BV^M!gw1BF`yr(u6HTz2Q# zhN+=S%pc(IbS;#hjg!7$X=%CWE|*$bT1sOYrXpW#9&RYl#VFB3k?(OR zVCU0ijPkL(oyoi%>atQdRFzS#4xct5)~V-kA5QsRTJ9}c+sXbrW4vEqd>H5xv#Yr~ zQ6CJ~S*z$3uk7xU1hIi99B79w=gFq$0Rg*jcCAfU^tX?OHuD7=UK8B{5@)JcUXH4` z4RLo}zvOHp2Ss4We@pM`H@^|XiIvncvl6oTLm{w`z4Ykscj+{B<8R>_c))W8L!*2~>pfMC|i`?7u4?yHi1 zHNoh_!sV1Ub#YUp<|HzB-ZDV<9h3JVE&xv;q>y6&$u;e7AyREXBT z4w#!QmIn?yN;0o%q$LLxKFcvVtPZJ6(M?JQXLb#Yy~s1tmSq4_`u#Y!nn|x>ZST;P zI_9jnR5lGJH_+}!e8huK_fc;#u7(0}-IVgnt_Gs@y5p)8(2Ts=>BrVaZ%Iy^l4Q+k zZlLa3#+tzmI)xqA90yjcr~rjXuIcVuM$1MW7uE*x?9pRfOV98ZD)RWqqed zLulc&K>uhR3H^DUkuDkyKBSt$aW}2&il~8rJu3tUgTMj#sO0Yyd-v=}+tp0Evf&DI zC=pV>V%j7Qjai*w%eYDr8{hI{!)IEH{GRf9q3G0pFRA`H%2PUeS?W&AS(_X*59HP0aF8)R{QUF&-py1|E?cEBJWQIGXwYW*KY3ZzWI%vyG5D$TV-t9nyv-IKh2%(=wBLA z_WnTzd=|Y-ILy0+-81hgOi>&8=;%+t;^p7mbf_d1D8Es;+~ecQg$kvBH=!R1C#+GTy^agE%8PMd)rl6Y&^Xr z$h`A`T?0?o6OYR#=BK8ADJyJ8U|&5yNk_wAjxr}ghdqaa6YENiP+VyC8DS^Jl-@=4 z++ZnNYW)#gu3KXY_!b9E%M@OPbKV>Uf@{^>bo64I|r{Gg<6#*i0fIgg+2oylp+TJ~1-F)~V;*ySzK1 zp>i*<$ye9Zmhqyr4yAXq#I8OZFpGExo~w#ffc87rD%`Nb%czJ12qXmSV9;(x_b4T^nCf5b|-A zABKzV_nP+Zk*kTyX3Bb+i7V{V%Mhg?)c@FSU>xpir z>_i{=>MoyPrI}gj*cp92sxQY%tj7{|e85rgAuq2NJ)d;&HQ~$B!N)fJJa9r*FEsMU zoy7Q@)7o>+a7s9{JuJgRZp2|AEgX_wqfU+Q63}In;t|(8uY5+QSA_p;kwvZ5lPShjQO z1HZi~*8G|*a)=uNff5fAqhV(3sjUEi%-pdjCJ!`MoL%E&=P7cXTkd;-WW#nhnLtVK z?WE9;*z()=7WNt~LF0apvx{ZVz+|w$tjc9{=t=LRGDwIAr5*7)_!q4&RCW=>7K9~G zZfxV5xE1dq#1^@Mx0Ym1Uj6&E{PVb4`r;au2P`w?gxEX;0VQY2F4a0U8kh-Oyoea4(N#`>p`=;$M z9la@O1*g!bo{Lw>I~~%-$XLyJa)a81b&U){h-l0PBpSPDN_EBS#3WLJ|JdMR~^Hgd=C9e05$}R+b zVyykgdF90&il1wu6z=eKi|+{dVq8j;%7z(x7JKT+SzvGx-YrIYl7K*!HH6*BggsVFjq>T(`JgKZz6d7S^j%w!9X#p%e1rOT8?Fa=^nn_*RvSsEu(p zIJ@;8JT?`cH#;j$zk|5O1_&Gjkt@jscBM>b>e~XvK_Ro>Q5V`kGcSpEubH?)&Pe?t zdVO`_ZBGHF)?!MW>#sY{l^#lfh>mC#H3&Cf<-K^w^@FsK*t6p17ec{UbaR3RMJ?I0 z{e+ntu6{H?qpE3O?%5|LoN$Zv%bv;F3*j5AMQoflExj-~;NBmRkTkjE+wgLG|7g{1 zCn~PB>h_MxSZQa+01j$NS}G=&qgv30H!`FGH#k=)XK5SazRC{{94s+O!HGst%Mna+mk#}eZQYh4DUMZ-Dw>wFlDo2`o!l%0fc2e$@e}{G=&(x;3v#q7om)yKbmqwhBBNLiH*=3 zj~q2v!54+EoDT<=X_$8lHx;@l+(|)RZ*BzOK4Ptgxv)%RzlB{!kjh=_((H@h#ui)- zwRr=4l;lHx&=3WoFKpFT;YJ1k-o?A=VJK(fi8pkMjpgMTrUi8`8G?nRJkyW+B+&wG>$F&ru-_&zTv9ZM*hJF+PGf zibp+xp2W=x{dcAFpwd4zCN7ht8f4$~Il+8#W#4$V+_vWzk~(htPGBNO z6B^Fo<&LoftK+EDQlhhb&VWSyrvFixy6Vakl~yTozf16xTZx1bG0#hGXYlYwzqYZ# z$ZTO05G_7afg^gbS1)ujfW#S?+^66fAfiJ0mn)yD6ssASCB;rC=G|LwUHjWVzvUcK z&_@2Qr*5qCE}j{o&WE=HW`l{lhsOyt8;!uii;;G%eE{12(*~iG!+AYE9s>nbW5GNt zk=hm&%60PuDfFKpkU|=04BO#uSuR$VJvlr+so-WPcAQ$Lj~n8q?a(+S4dm3^$iOmC zn>qYEDX<)Ee!Toq_SaWpL(m9I7fQ4SRXtSgA{5vJ`#GWfBi4I|(&OkX)JI6Iyn(5u z#;MeriR)gP-?=#+0TZLNSS4MM+vP{b%p{!;N`#aNdK_n!m#}55zOXtVyxuPz3d`ym z=br{Xh9=!}y>{f{bA-#zL89N?Iu4?mwGDe{5}X4E^^+h*RP$9W@d zJ4@99nd$U^yLZllBKgEfI@js4f^C8)pan9BSOv+rLvuw>QxzU2y3i{9WNHwI#4>=? zLH7Kw0_cr%sAlBQPR-FZ<7K(QI2g1GoLM(u_2w`(hB~jTXAxd&mcQY$+=s@W zXZ}9tYk!>au)_4V#y6Pb+oGmhSSr9FEgu*o|0Q%U}njrOtK6Vraj=LG|t7vgy%e2M5(N}==ayM7?FWp>t{{E=Uw zI;Qz2(--^wi^OKFU2{|Dm?Q=Sz72qy_4*`wk3hb&p!XX93SpbGHk{<=47!Icw94dM+B`<8cd{4s&12=f_o>!YQhD`M7Ry(E+DDMlf>zqo0@c6OLjiq$Es< z$E}kdF&HF*-E_;+)(iSd|2b>2K9!d*4k;YupXwpUm0gJ_AC-kl4_){W-THrt9y`RCkl5d$A{&~pGET^okp}iq0J7b4y&x5}yyS&{Z3=N@bLfw63GUWs?eBsM z=$Dqda@iFKCcWzT2Pjnr%-<}+xRP(oTYLfDf8?vrqAi`{^kYnzM%(1Ukw4>S)<_z~ zt9ByD>|aVziH~&{pn0>D1X+w(DtHnuO(re+HYgK6^|{=uy%uEj*Pq-!v|~;QlX;v4 zkGByrP*rcou^r?DoD_($0yDNCM&QoR#$w*P>uG*bZ=m|LYK&1hc~c{dU{!ldRL)f)SP=U7Ta8*bw8BH zu_4?62(Kt0;oPb5otYgQv>=c>QB$4*p7na(IjHK(@h5slAg59U!P3DTDFKo{JqM){ z89f|E`H`L)>HaxU=~r}oz5Pjfu>#Ek5n*sh=Sm1E^r&Bg_$Q!W-SWsXIp0*c1Tr7~ zc>Z8$gSQR(1Wd%{H`?FKxKq(q_HgS9&$U!iTexG3^q$MNEIR9pB-z4n$i!V`Lkf_n z{FXZi1vtYKi$e#GJcJEJ;fAg)^4Ga?vozA z;;qmm1w@r@%WLiZiwL|FIZHXWrjwFIdWOZFm(XHBk>4sMi&DgP?wAV^o;HcL^NJ-x z3eZ*64^qi~Ec!3r(%Um&^9n}_`+)S z6+>YRE&givP#8C{v>cGg%!isYeI4D2l3&eLQ2#XAAwu_FzGUi+%4XeyjzpjWdN>adod z#fiE@QIIIrM+rnF-`{;E6TB-rB<$`YNOK&0(s?o1n2C*z9vS$e|%1q9pdtXdm zeduDMD|a5*tbOo^x8Lq4zi)4MPVCtv9mqWLN=OOEMX07y+ym}B%{RFCY>5tQMy8p& zIZ%*0n;h#~BWm36W1^?3wEE(x&`M}a3pt+y({-TSxsK(7;wINl1tBuWZeJnsGADO0 z1#%|mzfTpz5omioKFB^hf8&siuefa4V5umflX?f6lQnsH`+y#5qA4yi>}+?t==cHLCSr*e>~h_23Dr}dKVvp9yk~EMzj14R9b)fTM;V z2J%TAE&6HFCj~tEX*H}AOaHJ}`Vl7a@=o7xrbI^r{Z7+fXR?ViN=2Iq$RU;?(4v5M zke2CyCM&`&&y^QRP;4N}I7F51Tl@uDn1Cdqx$29LOLbPjRKd60pz9`}N7%x!W};FZ zz1vN<1rh7CkUnr+JHW-8YGv8z;!`&~&bwi>9a{ZXGi8Od8(e!0nTU0H+81~isxW;oet zJbxSD99;A6vr2lyr32;9F3K2M%Bg(=rLL*rT&9%AwIRiP?BNv_Z`OzlHg>}otbF^F z{g=L0Ao$L)H~jP){q1~n%@{p6vf>=icctb-NyYR2bt&RPdJzrs_GE;YGGL zuS_+<5MS0-iuY2f*?mk#1GFQtzb;1m@0c_s=@%5N^3z*g@kLjSJkM#;nDufI(tbT` zVgD`I?wQH9?NP&xA=7u4TcxXt);6p8ie1a@ncje}d*|KIMX#51P5b=aopP0W#E8$Y zkQvYy`B0;ZR}^oyqBx`T^JbBl4V}CrXK4x*fZv5-4*B>tZdPYmK>L#bbHzArs;uJ zk1sGNbcurK2pd$q`}nuv3)w*Hs##H&Ps61<4$k{2RTFmA)&!kQswEkN_a7gUWq!Y( z@#+hyti2zmx%-t+Haa>~K6BzhXu0T)6co#&{d**1s}GQe$vLa#S)Z>2Q=~nfP12LnySScka`hCxU8jJgt@?u zSBPs~rh%XvUfs2a;5fEQnV~MK(f*l5S?KlklHbMJ@K-X`DMQmbV~%Ob^4Hsiuj4G( zWbUz9198;30KaQ2!{>P)vkC>i{PaWHVW;uK5gS|&7V(-mm22DQ?wBPwsxZRiuUysl z8df0e!XQjOn&nG*;A-659C}ih);q*xWi>gSUiyRm!_=|UF%mU0aV+mJ!*6ptcq&Vg zmAa~@28wV+;7{=((Hzsn?X=YUOAt|E zQ$qqZMJJL!Z0y&j|LG<3V)3e=nqaZ6@Z>ae=a}N|v=!N?qiq1joisH%bGrltDLUfg z^&!?ejC?_E&AT=n<6fm=rX`ajTh0KVy7rAy52aQ0qdTBMW_OqtD9`p6Mo~HUrma+` z9$f)r^{b$)cesKB*e>K4T+*oi6svFUwDX!hn55z)@$I@U1Pt*y+J+VW*vfSNnt71& z?NNrpZ{>Sz5L`KvlDCk1T=si5CdKv#h(XLPpRk8L8ncJS?vk_**kw1Cb6%R9T18II zzc?toWaATjOYc<(4`GC9`0flF>(^Teql)WH3mBdx3D;KQABWMrr&uSP*&X3ffn*ri zUGF(yU!kQowFbq*ce_54LumM3xn9}GWX(Z~8r?-l7NV3-nyOQ`9!|Lw?Wt+Gwd1VR@LM@G2-kqHn^8>hCq3K^+u8J&CB{*=A@52x!S`_3Fx)5%wgbgBua z`kdpJ-V}gi*CuB)0R_GX!vQ<(=Xf?p&NXyPuqYT&8c)mb*cKdpAStx?^4u2Y@^9Wd zf9m!Uwquq67buull+~kyRSTFF4rFeXgN={5J&Rb7ZDx#%o1D(M{fD>6elstwRT@~q z5>K3_!?A2oN5$2O%(G_UM;?ax2LlkF)6~KtWZC}q`qf|Q0imhm&+)dP8;eh48e<4E z-!}rWEcV}Sv1T|fDWgNFfC*zZ_l(N3!%C?zIF$TlNC{Xdf;pK+Or)Bt3c(O-Rj6<^ z=4|EkDPrC(>OnFTR_gT-VGKRa>&#@z!MtW_s6ehe0d<%>gp;uqIVex<`=>uB zujuJA?sCCd$n4#oB;yG4jHR+{eDlB4t?^?Y^InLf5FX%ZnuRt=o;1#!A;PXNTummt z88a#qLb+i^27@X3;<$zNoBThFSbEvUbJnsO18msQh|p z9QsgG^~2x3w5{ryw?#)<XIissO$Z{BIUl1|&`t$P0 z$U!rOqRA784jG}m=)y{2ReNV&hF4E3Kt4T8%^!*AGJSuzrA$6yhPfZ2HIj>`D|(Ye zfAGXb0UL#&f{0*RYAarP3Jr##x}zQ*|54sja(3g|UvsT~;Lg=`)fySDy5@IpK&(3% zVI7|+!4O@z2m~bX43gDSCeI%_Q*&mZq1=>Kl7p)%x@$h9<>RtxT41CIAFQxlI5Ej7 z?!Kq6;2q$+N_ub+5`0W*2F;xrA8>&1b+4HiW4&Ot5YM}@n6)7GkSbQKc=5nFWF?fdtmXMC~p>^f75p$%y} zD8G}->1)TTe_Fbcv&NFRA~>o8bk#ZL6PXV zG{ zQe7>jKB>hL(Ztv{OQ|=v5Yn(&`rjfhr1%Yt?(MKwYYR)@2j3{p1#UFEgyLXeW>hz_ z_3TF8nz{Po$!H2UU`yqY@w38P@Y01*>8WBNs;%!*cU$Nd4zOrAB4j7Bjv)60>=6fDml{Mx z6oKdknNr>;;IcN4i69W&F-v9fvLweHS=xeX)n2f;d7pYf#@PD!l66{ zQH-MJveBz&9J+wNbky9^lC$fv*&G5x|EIMQ$y6mTPdMlz^J* zmvSn9cUCwIi9Q!5d9=R1er}o~hf3wLU+&kCLg*lD<*+g-b zC3u~l93M7DLkJ8KpM+pmfZ(2E(QAxP zGr|gQQYip1J3FfjVlN$RjLh{e-t9kY&)C~D15j~Bd#&L&#}2dueE3w$geeGEH$V`U zac4mM_aD%4m-M`u?8#Y^lrXgN-s5(tv-YTdZ49G;b3kqR@SO>+aHwD6C5l$S*F%9N zq3}C0*0LvOQ{4IRozCddQHw6zMAH`--88Cm=EtT{+*@!+Dm`QYCx`2pphP-K^gO?k z=#e?d;(DUjy2$a5i%|c+J8_1lAPRy4wdy&6!AKPtsGgRz787KG6MROm!N&Jk9djx0 z)kFVBcj`#2#%T8D4oQ`B%5<|KrRe!vNa?2Z7S+D2Wm=VM0;k79^M^D`^ z)JSS4Z3!^7UTO)^C`$6Vx-f`3RiQ1*KEu82GcvT--O7GX4U4A&R%J)VlGiYA*|s(5 zt*9av&zi}45e8$2s$=y`10ncJ^gyZUT45!uW_p>Jenv#ZwTp5#P;nL{ltO&e?>x@r z$qFtL8&@+xA4V0qXcqqsl4ILl>7{HuRyqP&3^#F!lU3vaSTOK-D+HC@B7Nk^B1HV{Y0{ z$?>3qJ||8%rw9DE%o|Oit{PUd^snsZoyYge$w~CQlS3*GveOz;H~i=}4zG2WQh>G9 z{0q6QVgZ0OZ)$UFA{+XQG`z-!D2Re-$9|8TSP#2p$Vpj%ip;)dIEoHz!o*33euIr* z@t506Y3hY1s+Z<5^6&jlV+OBO=_lTtO;77U62_=_CT^M@fB!l~2#2`{uu`C6YL${4_HEht2J14h5!B>-K`C8NMP;U*(t6doBOU-^_G!M?-{#Q;)I)^h3vL(+5EY3X4 ziaz56PUfBc-eVR%ZEB5GK02u>^u5mhgE%D4bV*j0$SAgZ#E!LM1FwRf-`3ujS+r3&IHP~W2sQ|S}o>~-G;I40g_rP zfcM+n8a>iC;AIB{%gnVRDvb6K7+hNy!=Qa@65~VSYb-@Fo|3K~OSd~Lxb4@{oObb@ zc)aq7*al+l3Ch^P$!LAgq_CAbF`D&!yMF<|NHgPjLQVI^+WV`|UvIAX{%XafoNRju zBh&}d!+}KCLb;iE`k+-Zl_R%mgplbRsXMg66Rp;zqTF(+q|fjWDN+f=+Os?!@~Vqp z_A4AgYPcEO{0`MvaW3C_y~8`q@w)aJTONDH#)E|+ioE3}*k!R0E>zav6>EHo#R4+t zd{$`}DRulkbfsP+(rM@GG0*i$Zo9t>kU#}AI*~^M?`_)jmm`<#L>aldz0`fwuudZc ztT;p1!y_VOb}LsDl}AOySXziYpJxnuTzDxLs}wEb-jJ2VIETMW4%Hb*0*6eQ^&H4` zu|$iwlWpmmveXF-(p)^<^US84#XczZ7d>EfG?igQp6GFZEjUKZ2ijXGf8ValAPCSC z){+p3356QH-eI>ZqIuguZG7LJpcCf8IO%UyTJ1qqG?W?E?Fo{)7JeV2ghm!tR8-RB zQ$Hq%J*@5*N1J*ObuPvwLgQV>gmeMwxl#u0TAc;6nD6>}gKb9OF}>s{i^HMLFqLJ}mgXBZ%%6MBH>ax_L zGZl>i#ph6KuWTQtQMizgnAaY(`|TPTpz&TdCyA7jFgY&9M~wf4w=++oC9KN^tZ`Os zg!)v}4C27jhSKIbF5lJ@6!1IsRy{r)gZH$>@blq`HGwDDn_=ICpypKCuO3=@(CP2fYg9%zOUX@pqlmu{Mx~ zR8@8=xodYZQijJL5SQJ>T0hu*#;%<+*Q7sI-LTz3GR7luZ#W4p zZZ)RzT#N%g!We+B|DqPl$QRfi-p6dm|Ja`M?}4y#bB`k^=#W#^DD7R?^w);|RyHS+oN%~#BpECT)-*>i{&ll^BzBCt z^=mFU{@1n{rurz$5m^Pt=x*%7@yXYEOZLHP2iupFBn3_hj1j=6W~HniS{fx@Uxb)TOL`g!m|+RgEu znzQ%?hY963UdS*}3m5IzR1R31kcC0-|H;q4VQq{ae8S&8N2XJC+2J~DAKMF@I`uu= zw}=>}A!FsvNp-}&tdf%(<)!-Bq`@0b&_hvze)o#bSS4cykQ;sX(Wa!9wDSN7;4eO2 zeY&6b@4M`RI!eO19E>Db{?cb6w$lp;-m{ zARTor?`%+f-*bvzYu!QelJ0;&@>p1I5`5jCRW$DJsx&2$Ym_485S@)`N*h=yNMND3 z^TD8Qdghebk!F7LknQ4q5_Yf8-AIp?KcbkwYr!2dPs9V zd?IxwC|-vRD#sGUy=$3*~Q`;UYb9^oLm7vE=@B_;8d=Ud(K7xNpTprx)r!udwXvUkd1;()4h=8Pi3 zM|Py`Q=na1dbra)3^e@i4218BNZw1CKS_*T`$nIq`kd{0#++hNYR_0G;l3(4mY^VY z>)d+3aKY?ZuKbw95&CYKxv4l@l};MK-0kL!z5wq>Ys8zHFZDH!Cpb8C>~=(7JOM+) zKgp&5%X#JQ>+Zvq%LN`x2|r{sMuLPu>fP%SLx1*7>2ng|bEwFg8QL%qbb6LoDukp5 z2Rq0YYZ$b@)C#~sR=B%p;>nMVK`8)-5_9x10=(h%HIg`bL?EbqaKsmdH6Z5&@l z4YNz=C2i_Ip(;5!_vmkU_eHfxSXZq1{!Lo)K@nWcmrXEPfilBU!(xC zB?3oBRbd7iF~mp+wl&H1Z92`yaZJxUe%$uKov&5=gM^K~scuH##7Ce9odcyAXkhH(Vmh6%cniD zkbd&7>d_S^dORGOvMF-xr^8V66=IdD_Q>vrn(Y<>CxVoMgg9Ommj)Vs`8R5*)NMi& z$(z}A*#nh*pUVSAQH|VP9!HHu^eLOLF+7(Q4@X47b9pa_3a8x0bL()aM z$FK~0tjMgPO^W=_h=+o#usgeN>{zG7#FOh4=d^OQI+eI3XmD`rxJrr))g2xnk+=20Ee2agTl z5kmCt{J5EPpDrmuZjB%BtkjP`bi?AcpbF1kbewXK{vhatiWoiKGH0Q&NYLCIYJpl@ zsHIZKZ2CC*LpgGL$?4Z?p%EKB#5bQ>iX12|(BPkmqi*whYOXw>>=x}>FbdBuwfm@Y z!$Ly4*|W(f^`;u&vABO}4vFiPac`1mu^!z!+X#tW3)-Ha?WkoQUbo30{Nl&{I^Nuj zNkd>Wu)>Sq#xgJK0jr@6tT5)<&RHKOne^sTVEtDsFJEt%lizrgWbEOz z`wtF!Lb;M%Fe3}sw?)!us9}@?lc|(}S2ptezC;epfU!8tM*M z;7G`_O=oVDkM$}&SC8Rm2D$zRsY?gaoO%mG{}gftbUA3(*MEkV%%1x>X0gLH)ZD%C zQc9j9C%{)`$&q&@9jfMA{3jfJW?!s;0yN0w%Uwyp)HsMOG{gQ4hA^> z88<5D5`B5n!Zvj#8eq-OB8myqYf_?D77H+Y(>jKtt`Pp@ECnbl3KCfP?q!U}rES5| z`hbsjLF(>Q;`RhmAYnq3mLYSfa5MeqX=!p!++@THoblGcMa^sJFq~~PliGEd1H6Nl zGVlHuJ4vhge(T7Q`qrD~N1x`OsRfsm!c=y3#+CxZLXLwco}GVj^OYz4pXw|J6AmD7 zX%4hj1-7uHF}S4=Q{R1k%0j}mM&v)rP%AVGWQH`BKa){`guu07zy!A4*;wQRtPIS zY|stbBG*b5u)O`KK|ylvpKoA$+gf7v51R?hl!UH&t(dH69%dqE=BAGwy*VwZw*V+E4<5~wgedgV9s)P=F zV!cyP?P0$#^PVD~``nv=5ZUYgp)$VB8tovfBRxu&Q72QnRhpP>&aF)cYKL$p72fCh zanhpfaKf8Mf`!(?VB?;Jx8xY)iw{qbS{L=_=GX7ko3H1*T=}pXu8J%5(7~zVTIuY{ z9%|5tY8ntJaCc`u+$yZta=SbcV-=j)-JznAlVItvT_@b6P&51coyuhlFVT{$%D`LC z3c=aHWDxGwU3wX-Z*Ykx9x%r)jf8}XxqYdt-Q1QvB4P`(e^@hE)pc;f{w%th*0?{)4z=f`dBevK*yHD&a7 z=p1u4c&c~kfTtTT8sYfqb^`RyhES#`SB1UhkKhAC-Mh|`0oaE0H+lxbkf7BVOcqIm zmp!oX7S{zrb2wEWzWc5UCW5LJE3fYL4v3tDNWLPEe$PG)LEI#w9S=lmF~Cg-^Es%f}*Y7gzR z&YIa}ZAprr^o>)Hl3S{i$~gv%;@q;DZv>r8Tfi3qeoVEV`PGmgHo4nezBiaba`M6` z&navK(1Qaf;=m>OQY`hfnmR&1h|?!# z4Wb~Zzzf^`%ozsokU8)GpfbJU$=$KsdRNWn`XC5rEO=Y$!SW0=%5-Rs`~xB`b6JY; zZ-sM63YZkU@{Z#)*|9CBpo8u&5f2IX*`Fgw!?uE#AhWn#-Qry=x@A@qa5ez~#;ly+5sh}UyuPbNYvd7)w z`fOmSE59paWryCLQu2Da`buwxT1j6#D? z*4mTkjW(=2gtSZijO)c7FgI2J$lEqh6S8DjHRgUlqP)X=<43%{#_VO4g&4CP=?{+Y zJ&=m&u9jbje#jX7ZZv{-9j50Qu`^J1e&|WI2(fmLuF+#OqD zRVUDR_Fz5;+_1jPms^<0hDkjXHu_Ay@_^nJZdwIq;|U;pw(~Vg>$1v>*I2L=Pq5tH z|Gs+NqQz`?;E9j#1?S#R$$A3MgdPPRS8UiNIqi72B=vUN@LP;1rw-E{*chKSC3BnA z(U_A?o}-%N-HK)KNMJuNo)X|Om&?-!@P>$L#Jy^lycfow&-YvUrU7<+cvooekQ$y4 zCI%7su&O8B`RawvD+Gl1!_DqOa|rheqelnYWx3LboY!W}QPumz53h3xF}uL^$G^8oNx*+)XXxXrmtGj37dSJ*D9{(Dw( z)$Nvu2(%d;i=s}2(Qh{}qi5

ZOTCY z`)NwT15kO7gL}2+kN0fVraN+vt*py4Z)&6zIi5fAF+Z=@IZ^`V(h~--42Hm7LiZE| zxS4$b^x#t)h(GG?7U<;;0X#K?V-Sr+1NbZEa5)zRjo^77iUC~+B=>1%moCI#Sh(#i z4FQY0$8K@5obX)(aXwl+*hqUkr~vLr;(*9}DmTW#^bvx(&knlV8$7a8r~W6U*-P&( z>&M+fJ23#K7cFZE8$SdGx1Em!_m94V0}YVgXy9GB(E+G;+%DH*06><`0}+Prxfw@t z?;(x1)Ga3v@=U9bxq$m0As{=dtTX@ss@OES)5o`NF~rSC1`KUgChryMDr5!#tZ{iZ ztRZy(|Klna|CC8ad{TQJfGzU)20u|%EmLzG7@(~VT=;0|2?3B0rY;b3*}dPbk?xFx za=+}+_9e0+M~}EVS?ipqlAhfbh@ahUZgwi*0(csT3=t^E_-62 z3OP=G97E@%BDAs&iTEO%KMb#q4u6mxraOE11YjJRiRCO85Sr)W8(++ zU4t~ppOt$T$JsO&|9pB3^he+Gdj2zs>_E>awXNK*_o=LguzB}nU^rbyDd)U_fL?W| zIBKEXf+(4WrqYjP!bs(}&D@adM;UIFN2C5^biMU=%Yd#MbEtq6AMfaFAS4c6PxASJ zJz1WL-60^)1tafTiV51^TGt8bC%y8}#|r?-;;HH!LQgspkB6#F{RZ+8P78I=$KisQ_MxIes7?4xwO4X!s3*!oaAj7FfWo8@rSwKIYct@>yEO zrw@SlaZLkqV&7>-N3e9>(SiqKZ4u-{w%OSN!p%L54=W}JJUXeJjzcZ7=i*GacmVdH zU)GL@-`^3xyG%f8dcvVC=zv+@yrzC~+ocwpIVvaBQcPw$M*`gDhE*%zFYN$oHmJGS zcY0t`qB%gUSR|M4M>H{&7FDTyAn&0);ObA%vnD!j{IbD-s|keJaj;XM`+)jO=|J zQ@(QNV#4uY0Q`0cWKMUk{Xvg=(xtaT(FqHt;Nl~Pm9tjP+M`3q!!Z?~Nw0Yf)@z94 z1`}zFcbl-)mZ^irIVRJs5(cf$pcBfw0hb+`u>Kr&bWvOCr3H6S2I07{#=YJ@@$Ul7 zMdBa=s5`rECKhY@hj#Ox3uSNLph%kDGOVxjvb@8zO!G#}9qozW@1VkW30^(cfdQnB zQW6-3JAzkMF514$#Z1C}v$X0i+VE|5bcR1+;0F?oLAaEBGz^&(&*EKNW(9W1)9er?& z=7|KEj~m7ZsDl7dP2%L~5(96_R;Xk+8}M3JQ{=ooqNF8l@l@2)^M&1{C&X55d*#xyNKQ zKQ>WSX%ajhf(0+izPWj@StF2HN?8H+&fKW+xUC)v_&pIrCzx_Cre~f2A9Gj6_=t&QtT>IV^p71Be z9S(rHpX(fh5XU1@Z8%ylMgSZ<30-7r%wbEGMFfZ*Ykvy5rm2irtgQc1d*95_;N=o_ z(|Ye6=#2mno?OqMh#a@tZ&CwIF^@tbl=X|Ecm@c-q9#~76viMkScludwU)~u*iiAX z*+*Kp1(Q@wV;Fy3*Sr362U7onFR{=KlNX;^++V5A)W725&WbqRYDi7uImV})zV&Ut zY=7dzdn@Cw2ex_XqcQ$sKm%$O+4@5VIBOH?7d(vD@QG;T`xhL`F$t_J#a(8OXI1KuSy=SSex<_-DsO!V(kq0-&?ppo9rZ zsBuO~g|F$D3CM6-M z@@r2~N<&OmSxQTcgdHCEM&%6&GyI>+BUl5H!hy*5+q2$og4tb{YxPWBcqB8brnpx+8Zy^U4+amu5`I^p4}`;7`V(V zw)csF)U-U2)KZX8kifUX7-QjifsuLn;Ly?j`CWrfIkn%s7{{CMEx$QG7Z-hMDf(7* z0u9(m3ils!PlNLxDhcM6U=z*AY=uFrg@pwmhx^0NJc4f;Q51+McRgF+D}Y^2@RMIC zR6cvHJX;0}i+h8-e7P#P!SwY}9`1LyXJ%xf)D~~td-;CzN9pVmc(hcI89c&-1q9y4 ztv&0@-Alkce@cFyau|;l_gW+X;IZ8LnLj^&fDqXv14D6L)n+=kLwq)AJM)r@Hv|Hi zjdd_gHn##F(Ko@3MIpeSB))i)5OIUE8NeC?Ab^Lu(E>Z*7&im%C@_HmLXz{D5dQSA zEBMc5htJqD1|KON*zm;$KMsUIhfz#o>|m;Vw0P}hGM$B%Ux33NVI1n`Z4NG)i1j`m zrGSPC8xyY|));b-1?TK3I(*M~!GBMZhXIfLD-*j&;`Ic~;4^y3b7w`t=+`V!ku3`> zaq+seroFt$cAIM=auEoew`bA9TJKay$YZ}tutgf(QUZ@DtMKJ)f zxPYZWH@9c@qhs6L)h$CJ|EZGaK8aj#VIQ9fzXu_~1aScM9ROkZA#S1*-d`pRu?6}R8%3c)N4jv)+z&~=ne-m@x21~IZKW7-9-0fuh?ljZ-)9)hUr)olPE59|#I z0??lt1p>_y)&wjLM4|xNmjI}0 z$ZuWH^Wc2z)e^<%_R#nKboLO(T@dbIcIyz{0c%9*U?eDzM=W?XgQmActqCOXz@T{n zy{(%PIq+c;sE>i{@kp$~uZN&{NU*m9!0k~8z(ew2F@ng~sj0yRyWte!M}(nDAXW45 zW&(K?k@1AdxuG(;EG7}Ogz3y7j`AR~AhPpb=>S&pU@ij%Cy}AMDD81|z(m(+aiGZ! zFmzyy)?eemps!;!K^zBqtqZ0>B6nlBLz;FOokETU@|+^@!(6OWY5=ObtWKfZpia8H zs=?K|VNT(^q4m4ePZ1vgLfz2wkeyvvw-628Nb?~iu%YoN@IAsBu*j$+Xuwcv6gFUp z1}SGa#Aa|4DN#5wn!kBG3I#%h$h&w*VAw|zTuH3=VHhNolDJACGo*-;ufB#llllw+ zSOaBAl!pjvg3C$phmdN*2uRJ$iMQdKMTz3Ew;_(g9`XR;U{Io@iZ~cxVsEAt=`oNg zMWhtrodMEetRLv9VMc=B^F$R z)i|xhIJ%+d%0D76x2D-S@0Eq_hvLTv=u4(AsL+=d0G*GZY z#SGyz&{9H8452jO)Bdzx11qZDw zaudV`8?AG5qsoUWZ#Z+Kj|W_=2icSAAP|Sd^%mMg=|Ii(T-lQ^Lvr<2oNC?@coQ9m zGW9&3lJG<72T5$OxD#|Bu7wbHA#YgR!tuWn3e)e2I>oi zI%NbG&qL9GBzhylOsaum4J!|c97y~|6qdXX#W|Q=1nYypqId}@J1Q@%Krm?!q+x8e z$UGSV$~Y``FkjEBji^%zW)#wJdmsiGR)W8zIDxP+NeyaqI5?0rALnf#cL2473i$yF z6{=jgDG)y&Vk%@$TnC6i!bo08CXQkh?$Afr=hG+J$G!>o4(Sa1bGUnudzi)>Z(uoT z2l+SDP82^BK1m$Vj7fl`fRYlcA>~PElLY&SqJ$wOAx*v$FD%;)gOnkG zQxfJQ+gHr}h|4!W$#I8Jj3HU^aN}e}ipbdF7lypINsU=*AT=Y)g};&fNGOgsi?&vnni4azaLx5Eriy?=%iv6oAYWxSNN;FvC4Cq3N=@*qg=!~ z3U(Fq%J-Q9+e2}N)k_hrfGrK4YLJu6)a6a-P+iqXEndZz=Ss@7e&ST6F&HA@?=o zHR(0WHLfe_JyvU^ZtqjqQ;+Qy3O9XhaKR?Gy*D>$7PmZJvA=S!#TJ5n5w}$q#5mM$ z#6>UEMvueiCJG%qMi@5~^=Q6;Pkpl+8TJ)TPEAD1fMeQYUR!WC;u~15sLa9kZiX$v zt&T0=-zMv!OS8Eq!ID*LzEb3(y%+hT0Jx(bRQBYWpF4E&~4F< z(TZRd;4Xr>f>nF4dw4gHQOVwgQ;@w%h>|3aL@kVn1iIuiP6eBbIg_-YwMPW>F~37# ziAZ}hMvjFVhe{W5)i>Sex(W48$RV6tyiG2PLXfnBq~moZ%3S!5J|T+mV9Eq3YYL+G zBvOGCGD@Tt2?$c(Dfqq$zQ-QU#gLACO_}gj%Ht#1R|h4^(tsJ+1CpzF#)MF*t&d(G zExxjSCEFL+N8g9Bh(btUF=kDV856}Kn;v#FR;@u=NVAr5C239Y8Gf@3>&Slx;0e=_ zWF%FO|1oSfM7T|KPU4ZqFW;e%Ln=ho`MN5;GoEW`34jyBW!-1SWz%HiVew$TV+&#JXD(zmVIef8H7ql*G_W+~9du6Eho8oo zCM=>U;wcg%q_h*J(s1^RL|sTaM1wYD1&1_0b z+<}~lB6(@V41%TL6>NQ$mV!-@tI~amdMQ`wO=(;yQ;Ez>+zj!I5Irmw_^Vg1kfWHR zFrv_+u%cL^IHK61uw_VOAZ5U1cx41fQBxdKpi{6?7*l*xtmwDsku`E^=&RezG>sMv z7EJo9l{9!XEXvW!&&vg8O{%!pDWA1?PF$dFut81@8rs`FHb53y$+hwaK4nKXcT& z)Lhjf*2+~27-t%J^*4-MXWK*(cFP-^nd};28>Jel8_k(D8n_wX7$6(O87LS}7z+*g zMz?3QN3;h$lHH@+%U#19DlA|xsLywPwsRoi4ksul@FsXi;7D*l08NlWAWxu2fDlU^ zYaDAGOBSmX>lup`dqI%OEzWanFYDB{?ml{!Zj^{_zsX&i#h*o%Rg-0z^)m}AD>h3n z3t^mk+<2T|yf@1v>nf`v3!58;XOR2ELGZiIy3Y59k>>u8bu!1#PH^^9%^1yfO|nha z&C5*>O+C$MO{~pG4%zEvJC@%MHe32QMqE;@LVr-sc~w^FXfMOsqH*zY#c03Rj?fNU zN?OWU3gYwUd(W577k1C=#&aWe%y~?7OnU5aEOpFt%(a}`G}r9rVb4#`@6Er-f6kx5 zKfvF>Z_EG0kIEmxugNdQZ^DnrZ^JLZFUr5gkL;0iMt|o0ePKJq9j?u~4ZO`+k5Z3N zk4+CoPeBjb4&elB)q53f)pB*ZExQe(ZO-H5OmIVYTX*MixV1NIr{MhTJmP}p)Z#4t zbm79|6zW{;qVRm@EcsORBK!M~&DK7*>=VH?<&HUT;=6BmU_v>$G5Y@c@AcF5Q`Z95 zBG$r$f`xK~f;!_nqdNmSvpZ9t@tzr;ES@}`OrB02{Ggb@RlxMX9KgiDY{1ySB*2&g z3<9_VoC8F`3&9b=ZNS^X=OArg$-ZjC&_KNop){x6BiW619gB8V);NNF?gVS_)Jt?)MZ3;_%eDrrY4#u`U09*l#%q? z&%3{;|9$^?e{9rjRDIM{L`>ugb|$(P-L6#7bvel@lrvVgO|v=Fu6vtZg++^5**-{1O5RX8Dq zEFCAKAj2f>m$Lf4d#HK@c4TPSd{kqoX$W$pZ^U>6V{~SyZbT=knURg=Lc~ln4rwjESyfH91uq^O%U_p;>2z7{aNH6>>dYI@@{3|D*DPO%0K3PEH*CKF2pEG%6C>Q z71@tgiu+pf_2bvJuM&l8BRD3mCa5NqCJ-ikCd50iJM24TJC-|YJH9*kBhw>QNuAVo zpHNhrRQG5tX^UvbX~Ae6XcuS)Rq#}JRYO&dOU6p+Kb3zXQ`J;~Qr%I#Qn68OSLszn zF2O2QD{Uyd{cv3O!+|Z>x!a6(+}T^u*y?Ds^zIwx{6n*AGItdE#@y~ zEH?1I&6dzr(iL6NSy2^`6nHD3-!A)D=Nb3Y<%;G??26;c1~DHxE;K2$C^RHAQ@mQd zX5dW>e2i&~U<^LqG+q@)hXuG?WRZVSc~NXpOi`+7lWE3x!!KH2YBPc|8ad23QaQNl zCbg`!^0h{^2DIe0z_c8+nzg9vGU{6D#p{deu}Qi&BS7HbvD?YcVx!>`CCc>1pX{>RIX8?MdSq;yLSi__oF_K&$AZU_3aetFMI&$UmnU<>|h!sEgdUE>Cw zZ=&DCcEbftL$^b7A($ep;ythfacgiRam(;Ba9i*~af)!TaKGWX;vnI!vSo2SSU1@K zInkKkvwh`qWIkt$WE)|l<+9{F;L2dm;LzgyX%fx$oil~?8*2mSHD@gAIIE!TvhlJN zzbU`b!#DR8NShu*GQ)hscNUu#Xol|%mEL_d|7zp7V!UWPyj@H)lGLlxqtZL`b!M8q zhrRbQZJ%bEXqsgjce=3%-xP;Uo~;)4U@0~4=T zi@J(NzL$Sd&6LVi=UlT%Xdq~C)@IPg*VbR+Uh-a&UaD;nZ9ulhw&`3VJ(@q-bJcQf zaJ@g;JcK_iJLEmAT$EdEZ@4#%YuK$zt(p7W*m%>ZP$y)pZ?$G3^iIg;`J3-F*lyPk zl3j!K^+S}y_yhaC4^tr6yr{Rlx2#uRBC;U9pr#A#$S!E z-F&!qI8IzFZk;eBHqsyI*z}>gxjMvO<7zzF>LA1}izKx4+<(wQ>8-8bIU}i*SrgpG)gLb-h<`QP3 zR3n$|k7I5(K{pRKBR8%a`y2Wj)*H?ny5q!SyJaqZdm?Wlc%s)t$3&<^3q(6aM?~rZ zMf|It59bu_@b0u886KXV;$Gi9)I4%72+p$3bgmz^#Lm#Jl`d+|7f+JcRrgd+W{+H^ zt;T;Oa&3S4E_d_o%=OgNo%odTOz=ox-DkpU>OKtlTiBe$>frp~3e{Jtx#F+Iy=Hx8 z17-`mRZNLhB~_tS6;+*fHFlp*Xx0SR_&S(;I!`1{b{Ci$*W5doo`xQq@9A!GmxOAb z&z@!|utWaA2BXfKb~|DlpDa(NJU1-tfWT3lN3iR}eQ)p-`q!YLKpwv5-L0hMr0+>RN$*8^L~2B7MaM&QkUj9uX)us>V3XlE;9XwD zz<)umfNMwLCHhHrX@$cZ%_Yk+#y`eKFIY}p&QdOPXgmL@I>!E8lVX!+la0HOOutjwZnZ1`iGo z?j5HiT_le*zcked4J|z_Um0r|-GTT_ZAsPCp82YIp?TEaTRrP7sbNv?~p z%aN7ElKLj?DvKmDE>$UiEZ>pb7T=a2B8@6HCGQ{)r!Xv6Dz`7yoOn*VqfSey%CE{b zOUXf7Pf|}>&vfN`pmdN6K@UTLj6-zFjpCKJCp;a{4WSI9_Ei{9B10!bGs8|xNlQx0 zYSDgix~|??g;&2tx-$(G#44OrhLX@wUhn$RDs6eoQY3t2EYxI$9 zgKWBNqU_07-&jF9Lwawz0^3~8q~?RBrKYQ9x2C41s^*GjW38UaZi$<{6z~odTVS<=|!VW`^e8W(B9t zZNqbO4?GVf4?_K=7R!ZIFNY>qq#NgPq({eV2Y6{i2{+&2$Tekov3d?-xrKlR?I=ur>R7NZyYDpn-cAx0xc6*-Q%La#-=$Uo++ab7)T zc+x8s7Dp)P<$iejuyOTH`ZMse;b$|4cMehxUS}F-QJYuf+vI2x2yyO2Qv8mGlJ^Op z$uA_n#VN&pjl(0l;>~cryq&6*up{vCaIOt*2A1_T^%YYTeysagYn;EWI{b|##fWuq zEcT92hEL7mu;(-1U`nhF@h*3z{qh0#mixD}#Vwyfs<^5we}&T=MFB%UvIk&y!~lA# z!dR9DU4IIEvSn&Z%0LQMYC}qFiXhXYrZ`PODsJjsQejeZvP<#`qnGk^V^)FAhvgRj z68_@0O7A@HvIirmvOu*Ds-LUKiZ<=VWctnfFCwp`r3;Ma5Q^=$=LEveW5SW;xlKcBZx|77ga6?7Qr_ z)*W9T>h8Q=HH+2sms93Zek!aqsorrIol|>9*FO7kwu+;+zQHBWrRYiq|ASoqmnIuO zZEK5)p>dY%L>@B_##^1$X64<=Y%gEi+QfS0j_D${@(V>Xr`@aZkZ~d1 zEL~dNSluaIiI#C!IcJ7!nBBW^s~k6hT>Fm8hmeb#i7Gu|eUy$ozwTX;#gKznkJzS+ z-bb%pWLz`d*jk)g@ms50giclu4S&2n{CpB|$g@1X%C=fN^UCwitKM_PE75b*%gdAa z+P5XVliGJ`JO8==Fp7!^N!Q!ep&+ha;qyc#Q%zMS-u4~F18N5^-CQ3cp))}Y$jlzkb;5R?>7D$Yk?W!&8 zjZb&hb4PVjXPH`c?QZpEs64rW{BE~N{M2M zVuukS`m{@T&^pZ?SkBM(e5z0%tYXv+s+y|Y*S+XS@vS&s+_7?+;|yI0O%5dtGYX4C z%q8|^esF*k5+P>6hr^@6u^__5_Yi;=hZ1*@XcwOrw~}Cr8;`NoGi$B%UfK6tzCxdC ztrBYM;1tJ8B&x-Gg-?fPMcm49{RDjwI)qq&|HS2Jo7KYNX>>L)F4vK{$R%J`v{K&g zarb@s%NK`OhuJfqt%$9iE$qSK!A=Ecg&~D`1)u^!Cb!U;!R7_SCd0nAT4RqLVaKe) zkMWAxrTHba#xJ%oYl7~rSJ$^kZf=Thz+;>>xVA*M-LY(Zx7Fp46ZjR5rXOxxySCFS zQ>|6U0bX@pKX1HGOjfMgxE$@yR*!uG?mcgOj?GquJp68-dLFZ39*~`hZ~2G3?a#YU zgF;~V62TKa6FU+$6Jrv|6QdGaku8v~h>!i!9#3a_e<15CyipER4pn|qZdNWXwv}ZN z5aCDjFn$O>D_MU#S`Z;|Qp_^FIc+*kIvp}?R(vAsm)1QY`9)&_I7X1YpOK!W=_Tty z|2+TXaJcn#uszO<=-IpHCvYcXG;y0sRRKDe->c>->Av)va#b;|f`TBSM+^5WQz$b; zGYHcQGi_5U)70H+r%RsE=F?_!CtasRC;c220cH2^xAae%cePJu3b~J-<5xNt&AS(u zyHvSx{C-#9o}`yOw@_RC-PlJ=$8ERF3Tdh7joEQILM&^1&+fjDl=m`MsmDyydfz$; ze4Cp946qD1Ow3qF40TM)y0>+bT1nb<`qA3-`iJ^ix(|<$_sQ3Ex$2r#8G0-3SH~Pb z>-(%m=TNKSIyz2&PW>RZn_n$yckpvsmwU|I;HpYlr%a%nE{reimC2S#l+j;PTBGfB z@yI-HxIUU~e07rN)^j4e3e`#H>2|yl+iUrxMi&)zR6ZS))(wpW@WHgzSALpVlu(cSSG4B9K23 z!x5VZ@p?x;Yuufk58lP`3jMxdB5>ous*mzeBrRXjKmohv6~_oSmq zRX$q5S4mYdSFW$^S0Av9vR1tqzDm7EM>*?#Gf{!x~;^yWj4E?VZo=O)*0e!wy4Z#bt%EHdmwC6Uy_@v%^#3dGXW4UT&k` zXTQSd#b>z(?TeemwYjAdo1YC|T$f#Uu9J^K2;C*T2Q8^Qi@nY4&3v&BBagKX#g9{t zkq$fNR~~OV-wTL7uw|t~b@31ae!u``X240X5CHu@p27Z%jyxK|o2h^zt`UNQCDQ)| zI>N^2WNv70@;3~I$;i&u85EU`(aF_pM^!Fvi4&#$q$;f@^_nE|V~1p~{ii8@U7fxnfVEjE>Wf$T9Hp|MZ@6i>>>e#;3xhFq^wTjblRxcOt5)-&K53E_p9tT zr!8y^Spnon30K`Vgfx&~o7wbjlGD2r!Tro*Q|L|L1Q52a<#HFN1Q~RNJsU|nU19D- z#|2?>&9je{I{T|)+=MzmuWU?QZ{6pHh3{S0DlYM)*lp?rb`1Ct^ z4~J`}zWW;GrV+&mwpqvV7%~9Cgbp$QtNV!XOpvMx(#x3Ks)2*3 zBe75u?t#!;Ceu1P1ksY*UV}2wH3oUqGMZU>)yyNT={XBH$sz;&z#bksR$LES#;!;D zDP@fPp@EgmH+Z{3o3#P2&%M8Kd`*aeW{}I` zu)I%)mQhO4LkRvJNIQt);2kkE1QiE)Oc|Lllr}=WRYDTWGb$_sgkmjficCdQ4x1R_ zG@KpUZ=SEF_NM0qbbneeiM=S)#zYqo8q7K^cs;>ok+bPg1*t9*o4%!Y6nvG1KIc9G zis5kKdtBJk2bYv;aK20~2y(BNa$IgfXVZDi-jF}*hm6MfU5)riG0isN48zK4kF?gO z%I=G$Q_D|=cGO_Ajhmvy3Q7YIfb-B$5x&d zYW5{b!;;Wpp*_V>yie?By08Z@*blHjlDEU{^4}v}+zTmrOE1kXKc+KOK0*Ka>O=*Tovhdy|3-#6nOK_`{fch-zv0tZ{ym=tD)1Q^^a~V}5y1SPmHua1 z4Gi$~{QTz@p)vcghJmyiK%%67rDaI-Jm>aI-Jm>) zFW|@vIPwCHynrJw;K&O&@&b;$fFm#9$O|~~0*<_ZBQM~{3pnxuj=X>)FW|@vIPwCH zynrJw;K&O&@&b;$fFm#9$O|~~0*?G&2#(M)Ke-}+Jifqy5;6!Ju`zKpGcmTXF*Gw_ zw6`?_g8{pJicpl7K!nGG2c1Tgk_0M&K7Vb)!~XKd6vH~v4*Gzzm(+9uNf`c0U?oDu z7NCR8QlLPCIO;a>Ebzh1C}LqIQ8S!@L~rQpFHv%a@VC*_;Lm8U8!Rb_x)&be5_DH! zAbOvL5{-chSx#CQA*PxGBFGFR<}H=eWo6DeX4yp%Aw*hhH)E`6yUmQFBHdb};IO?A zOlODpj8gCO9!cetJ=cA>ezag2jcuV&`A)OP^f^4hp2s}FcWiMZUBP{8u$c)QjChMN z+)~LJyTwszqkTsFQR4UqoY#FTQCcsvxn{~-&y?sZZvdIykPH?EVgaZTe-WM0P}qEv z800($50vmhx&9z-K%MssxM8xeH8yc)bhohv!vo)WMk+^~)H-gRykg+f_laZL% z8rd0J*qRBDsj7%GaFYoM!t;{?6+~4u6~#ylZT}&}U}NHJXl&?gNTR4JA}b|ILdC$u zBm)#d6}5p+}s$A46Us#%p46F?HtX1J?rvl3N zPtjjle%CZ{x3_b2W^gibb_R8z6Q~#xekT(L7f_d)h+9~jC>lDO|I_|o&HujMN{+{t}@G2!a9t>>W*9Elk{gtt7t}`+IcLf0PU|G)88e2cf9n6 zMEPGy{K*Z|?|T0gqQm{C*x%Z6^_O}esP1=}-+fsAQu_NyFgyJFmi?7S%iooM_rLeg zI#L9TJO7LFzw^fTyC6v5PcHTT5R`TKj|BhQ{`}p!-Y@mPcSPP_ssC43d%suqcQ1E; zRMyn>Un={ziNo=`#9z;tZI8c@_-|YI*E5E}^RM*&&5Zf4GQa4}f4(RJ%(MQG`HkiL zy=}kW$^Q`f(D5(#_1}$uznlGGyx93)Yw$1kHbohzUrzx5RM5K}6gil+=hxo<0qY71 A761SM diff --git a/applications/external/usb_hid_autofire/usb_hid_autofire.png b/applications/external/usb_hid_autofire/usb_hid_autofire.png deleted file mode 100644 index 369bff02253d7473f33d23cb592132f35982d180..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 641 zcmV-{0)G98P)e zlG%+*k||Ai4%8=T%ML zhSPQEyt6Y-=3Am1!eYE_=-5_Wc>PxeO_zW@erXbqKn z*v9|>010qNS#tmY4`BcR4`BhQKc{H`006m3L_t&-S8b3n3WP8aMTcdJ)HZ@1K`gcO z5T3{z!CK1#2*U#}@$CC9Ns^%bAx%?y;C(mix)x*1;}9o)(=?65 zar_AKjs6P0<2VlW3D&l4)Pl!}Q54C#t}>3}HK}b|@gJl|?&}GA`@0^P!!T%Bme<13 bLkoNWB5%k`78DJm00000NkvXXu0mjfs(>Tu diff --git a/applications/external/usb_hid_autofire/usb_hid_autofire.svg b/applications/external/usb_hid_autofire/usb_hid_autofire.svg deleted file mode 100644 index ed66f3cfd..000000000 --- a/applications/external/usb_hid_autofire/usb_hid_autofire.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - A - - diff --git a/applications/external/usb_hid_autofire/version.h b/applications/external/usb_hid_autofire/version.h deleted file mode 100644 index ac1f5d0fa..000000000 --- a/applications/external/usb_hid_autofire/version.h +++ /dev/null @@ -1 +0,0 @@ -#define VERSION "0.4" From ca71eaf328448c7116d4484ac3453a571e0f9c39 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 12:44:02 +0100 Subject: [PATCH 081/216] Fix favorite timeout with nfc --- applications/main/archive/helpers/favorite_timeout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/archive/helpers/favorite_timeout.c b/applications/main/archive/helpers/favorite_timeout.c index b46057d82..7643ebfc8 100644 --- a/applications/main/archive/helpers/favorite_timeout.c +++ b/applications/main/archive/helpers/favorite_timeout.c @@ -11,7 +11,7 @@ bool process_favorite_launch(char** args) { void favorite_timeout_callback(void* _ctx) { FavoriteTImeoutCtx* ctx = _ctx; - while(scene_manager_handle_back_event(ctx->scene_manager)) + while(scene_manager_previous_scene(ctx->scene_manager)) ; view_dispatcher_stop(ctx->view_dispatcher); } From d2c1a91a3ab6b9bc4fcfd5d40cfe9a37061a0bcd Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 13:55:31 +0100 Subject: [PATCH 082/216] Support subghz parsed recs for favorite timeout --- .../subghz/scenes/subghz_scene_transmitter.c | 35 +++++++++++++++++++ applications/main/subghz/subghz.c | 2 ++ applications/main/subghz/views/transmitter.c | 15 -------- applications/main/subghz/views/transmitter.h | 15 +++++++- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ab9155fb7..77ae97cba 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -1,6 +1,7 @@ #include "../subghz_i.h" #include "../views/transmitter.h" #include +#include #include #include @@ -50,6 +51,14 @@ bool subghz_scene_transmitter_update_data_show(void* context) { return ret; } +FuriTimer* fav_timer = NULL; + +void fav_timer_callback(void* context) { + SubGhz* subghz = context; + scene_manager_handle_custom_event( + subghz->scene_manager, SubGhzCustomEventViewTransmitterSendStop); +} + void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; @@ -66,6 +75,23 @@ void subghz_scene_transmitter_on_enter(void* context) { subghz->state_notifications = SubGhzNotificationStateIDLE; view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTransmitter); + + // Auto send and exit with favorites + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTransmitter)) { + subghz_custom_btn_set(0); + scene_manager_handle_custom_event( + subghz->scene_manager, SubGhzCustomEventViewTransmitterSendStart); + with_view_model( + subghz->subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + model->show_button = false; + }, + true); + fav_timer = furi_timer_alloc(fav_timer_callback, FuriTimerTypeOnce, subghz); + furi_timer_start(fav_timer, XTREME_SETTINGS()->favorite_timeout * furi_kernel_get_tick_frequency()); + subghz->state_notifications = SubGhzNotificationStateTx; + } } bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { @@ -109,6 +135,15 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTransmitter)) { + if(fav_timer) { + furi_timer_stop(fav_timer); + furi_timer_free(fav_timer); + } + while(scene_manager_handle_back_event(subghz->scene_manager)) + ; + view_dispatcher_stop(subghz->view_dispatcher); + } return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 906b8e074..6752b4e55 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -482,6 +482,8 @@ int32_t subghz_app(char* p) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneTransmitter, is_favorite); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); } } else { diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 2bec77690..5667cd59f 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -6,21 +6,6 @@ #include -struct SubGhzViewTransmitter { - View* view; - SubGhzViewTransmitterCallback callback; - void* context; -}; - -typedef struct { - FuriString* frequency_str; - 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( SubGhzViewTransmitter* subghz_transmitter, SubGhzViewTransmitterCallback callback, diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1af..1ae51afbd 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -3,10 +3,23 @@ #include #include "../helpers/subghz_custom_event.h" -typedef struct SubGhzViewTransmitter SubGhzViewTransmitter; +typedef struct { + FuriString* frequency_str; + FuriString* preset_str; + FuriString* key_str; + uint8_t show_button; + FuriString* temp_button_id; + bool draw_temp_button; +} SubGhzViewTransmitterModel; typedef void (*SubGhzViewTransmitterCallback)(SubGhzCustomEvent event, void* context); +typedef struct { + View* view; + SubGhzViewTransmitterCallback callback; + void* context; +} SubGhzViewTransmitter; + void subghz_view_transmitter_set_callback( SubGhzViewTransmitter* subghz_transmitter, SubGhzViewTransmitterCallback callback, From 2fcc3d1ae2f9dba3f07c8a1131e5e17cd4b1a445 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 14:29:30 +0100 Subject: [PATCH 083/216] Format --- applications/main/nfc/scenes/nfc_scene_nfc_data_info.c | 2 +- applications/main/subghz/scenes/subghz_scene_transmitter.c | 7 +++---- lib/nfc/protocols/nfcv.c | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index f3e94d2be..1a879d8a0 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -204,7 +204,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); break; } - // Set tag general data + // Set tag general data } else if(type == FuriHalNfcTypeF) { // Set NFC-F data furi_string_cat_printf(temp_str, "ISO 18092 (NFC-F)\n"); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 77ae97cba..7877e3c14 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -84,12 +84,11 @@ void subghz_scene_transmitter_on_enter(void* context) { with_view_model( subghz->subghz_transmitter->view, SubGhzViewTransmitterModel * model, - { - model->show_button = false; - }, + { model->show_button = false; }, true); fav_timer = furi_timer_alloc(fav_timer_callback, FuriTimerTypeOnce, subghz); - furi_timer_start(fav_timer, XTREME_SETTINGS()->favorite_timeout * furi_kernel_get_tick_frequency()); + furi_timer_start( + fav_timer, XTREME_SETTINGS()->favorite_timeout * furi_kernel_get_tick_frequency()); subghz->state_notifications = SubGhzNotificationStateTx; } } diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index c9025ee90..2e817a538 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -1310,7 +1310,6 @@ bool nfcv_emu_loop( } nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); - /* determine readers fc by analyzing transmission duration */ uint32_t duration = eof_timestamp - sof_timestamp; float fc_1024 = (4.0f * duration) / (4 * (frame_pos * 4 + 1) + 1); @@ -1346,4 +1345,3 @@ bool nfcv_emu_loop( return ret; } - From 38ba334a1ab2358a9fed715185fbe5bb41cd2436 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 14:41:24 +0100 Subject: [PATCH 084/216] Fix build --- lib/nfc/nfc_device.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 7f8518c7d..af0ef42ae 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1401,17 +1401,18 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { break; nfc_device_prepare_format_string(dev, temp_str); if(!flipper_format_write_string(file, "Device type", temp_str)) break; - // Write UID - if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break; + // Write UID, ATQA, SAK + if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) + break; if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; if(dev->format != NfcDeviceSaveFormatNfcV) { // Write ATQA, SAK if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break; // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + uint8_t atqa[2] = {data->a_data.atqa[1], data->a_data.atqa[0]}; if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + if(!flipper_format_write_hex(file, "SAK", &data->a_data.sak, 1)) break; } // Save more data if necessary @@ -1502,14 +1503,14 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; if(dev->format != NfcDeviceSaveFormatNfcV) { if(version == version_with_lsb_atqa) { - if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; + if(!flipper_format_read_hex(file, "ATQA", data->a_data.atqa, 2)) break; } else { uint8_t atqa[2] = {}; if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; - data->atqa[0] = atqa[1]; - data->atqa[1] = atqa[0]; + data->a_data.atqa[0] = atqa[1]; + data->a_data.atqa[1] = atqa[0]; } - if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; + if(!flipper_format_read_hex(file, "SAK", &data->a_data.sak, 1)) break; } // Load CUID uint8_t* cuid_start = data->uid; From 4fb63eb36b503530f3896a8541c6d74f10ef62a3 Mon Sep 17 00:00:00 2001 From: jl1990 Date: Tue, 2 May 2023 18:36:06 +0200 Subject: [PATCH 085/216] Code cleanup --- applications/debug/accessor/accessor_app.cpp | 2 +- .../battery_test_app/views/battery_info.c | 4 ++-- .../airmouse/tracking/util/matrix_4x4.h | 2 +- .../avr_isp_programmer/helpers/avr_isp.c | 18 ++++++++--------- .../lib/driver/avr_isp_prog.c | 4 ++-- .../external/barcode_gen/barcode_utils.c | 4 ++-- applications/external/brainfuck/worker.c | 2 +- applications/external/calculator/calculator.c | 2 +- .../external/doom/doom_music_player_worker.c | 2 +- .../scene/flipfrid_scene_run_attack.c | 8 ++++---- applications/external/hex_viewer/hex_viewer.c | 2 +- .../scene/ibtnfuzzer_scene_run_attack.c | 12 +++++------ .../external/ifttt/ifttt_virtual_button.c | 2 +- applications/external/ifttt/views/send_view.c | 2 +- applications/external/metronome/metronome.c | 2 +- .../music_beeper/music_beeper_worker.c | 2 +- .../music_player/music_player_worker.c | 2 +- .../external/picopass/rfal_picopass.c | 2 +- .../pocsag_pager/pocsag_pager_app_i.c | 2 +- .../scenes/pocsag_pager_receiver.c | 4 ++-- .../external/pomodoro/flipp_pomodoro_app.c | 12 +++++------ applications/external/pomodoro/helpers/time.c | 4 ++-- .../pomodoro/modules/flipp_pomodoro.c | 18 ++++++++--------- .../scenes/flipp_pomodoro_scene_timer.c | 14 ++++++------- .../views/flipp_pomodoro_timer_view.c | 20 +++++++++---------- .../rubiks_cube_scrambler.c | 2 +- applications/external/sam/stm32_sam.cpp | 2 +- .../external/text_viewer/text_viewer.c | 2 +- .../external/totp/lib/roll_value/roll_value.c | 2 +- applications/external/wav_player/wav_parser.c | 2 +- .../scenes/weather_station_receiver.c | 4 ++-- .../weather_station/weather_station_app_i.c | 2 +- applications/main/fap_loader/fap_loader_app.c | 2 +- applications/main/ibutton/ibutton_cli.c | 8 ++++---- applications/main/lfrfid/lfrfid_cli.c | 2 +- applications/main/onewire/onewire_cli.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 8 ++++---- applications/main/subghz/subghz_i.c | 2 +- applications/services/cli/cli_commands.c | 2 +- applications/services/crypto/crypto_cli.c | 2 +- .../services/dolphin/helpers/dolphin_state.c | 2 +- applications/services/gui/modules/popup.c | 2 +- applications/services/gui/modules/text_box.c | 2 +- .../services/notification/notification_app.c | 10 +++++----- .../notification/notification_app_api.c | 8 ++++---- .../services/rgb_backlight/rgb_backlight.c | 4 ++-- applications/services/storage/storage_cli.c | 6 +++--- .../services/storage/storages/storage_int.c | 2 +- applications/settings/about/about.c | 4 ++-- .../power_settings_app/views/battery_info.c | 4 ++-- 50 files changed, 118 insertions(+), 118 deletions(-) diff --git a/applications/debug/accessor/accessor_app.cpp b/applications/debug/accessor/accessor_app.cpp index 2e40b3c35..05a248efa 100644 --- a/applications/debug/accessor/accessor_app.cpp +++ b/applications/debug/accessor/accessor_app.cpp @@ -23,7 +23,7 @@ void AccessorApp::run(void) { exit = switch_to_previous_scene(); } } - }; + } scenes[current_scene]->on_exit(this); diff --git a/applications/debug/battery_test_app/views/battery_info.c b/applications/debug/battery_test_app/views/battery_info.c index 5353a2e2a..e32d1b461 100644 --- a/applications/debug/battery_test_app/views/battery_info.c +++ b/applications/debug/battery_test_app/views/battery_info.c @@ -17,7 +17,7 @@ static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) canvas_draw_box(canvas, x - 4, y + 16, 24, 6); canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); -}; +} static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { char emote[20] = {}; @@ -85,7 +85,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value); -}; +} static void battery_info_draw_callback(Canvas* canvas, void* context) { furi_assert(context); diff --git a/applications/external/airmouse/tracking/util/matrix_4x4.h b/applications/external/airmouse/tracking/util/matrix_4x4.h index 9934f6be0..83f151fc4 100644 --- a/applications/external/airmouse/tracking/util/matrix_4x4.h +++ b/applications/external/airmouse/tracking/util/matrix_4x4.h @@ -34,4 +34,4 @@ private: } // namespace cardboard -#endif // CARDBOARD_SDK_UTIL_MATRIX4X4_H_ +#endif // CARDBOARD_SDK_UTIL_MATRIX_4X4_H_ diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.c b/applications/external/avr_isp_programmer/helpers/avr_isp.c index 283c17bfd..1b9e2fd1f 100644 --- a/applications/external/avr_isp_programmer/helpers/avr_isp.c +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.c @@ -174,7 +174,7 @@ static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) { while((furi_get_tick() - starttime) < 30) { if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) { break; - }; + } } } } @@ -357,7 +357,7 @@ uint8_t avr_isp_read_lock_byte(AvrIsp* instance) { data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE); if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) { break; - }; + } data = 0x00; } return data; @@ -377,7 +377,7 @@ bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) { if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) { ret = true; break; - }; + } } } return ret; @@ -392,7 +392,7 @@ uint8_t avr_isp_read_fuse_low(AvrIsp* instance) { data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW); if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) { break; - }; + } data = 0x00; } return data; @@ -412,7 +412,7 @@ bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) { if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) { ret = true; break; - }; + } } } return ret; @@ -427,7 +427,7 @@ uint8_t avr_isp_read_fuse_high(AvrIsp* instance) { data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH); if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) { break; - }; + } data = 0x00; } return data; @@ -447,7 +447,7 @@ bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) { if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) { ret = true; break; - }; + } } } return ret; @@ -462,7 +462,7 @@ uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) { data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED); if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) { break; - }; + } data = 0x00; } return data; @@ -482,7 +482,7 @@ bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) { if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) { ret = true; break; - }; + } } } return ret; diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c index 0f46872dd..051d97e9c 100644 --- a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c @@ -111,7 +111,7 @@ static uint8_t avr_isp_prog_getch(AvrIspProg* instance) { uint8_t data[1] = {0}; while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) { if(instance->exit) break; - }; + } return data[0]; } @@ -348,7 +348,7 @@ static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t dat while((furi_get_tick() - starttime) < 30) { if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) { break; - }; + } } } } diff --git a/applications/external/barcode_gen/barcode_utils.c b/applications/external/barcode_gen/barcode_utils.c index 0a4770045..502014d85 100644 --- a/applications/external/barcode_gen/barcode_utils.c +++ b/applications/external/barcode_gen/barcode_utils.c @@ -98,7 +98,7 @@ const char* get_error_code_name(ErrorCode error_code) { return "OK"; default: return "Unknown Code"; - }; + } } const char* get_error_code_message(ErrorCode error_code) { @@ -121,5 +121,5 @@ const char* get_error_code_message(ErrorCode error_code) { return "OK"; default: return "Could not read barcode data"; - }; + } } \ No newline at end of file diff --git a/applications/external/brainfuck/worker.c b/applications/external/brainfuck/worker.c index 584bb9fb8..8fed94b40 100644 --- a/applications/external/brainfuck/worker.c +++ b/applications/external/brainfuck/worker.c @@ -111,7 +111,7 @@ void rShift() { memset((tmp + stackSize) - BF_STACK_STEP_SIZE, 0x00, BF_STACK_STEP_SIZE); bfStack = (uint8_t*)tmp; - }; + } if(stackPtr > stackSizeReal) { stackSizeReal = stackPtr; } diff --git a/applications/external/calculator/calculator.c b/applications/external/calculator/calculator.c index 1ca1d3a86..cc12cb7d1 100644 --- a/applications/external/calculator/calculator.c +++ b/applications/external/calculator/calculator.c @@ -199,7 +199,7 @@ void generate_calculator_layout(Canvas* canvas) { canvas_draw_str(canvas, 19, 118, " 0"); canvas_draw_str(canvas, 35, 118, " ."); canvas_draw_str(canvas, 51, 118, " ="); -}; +} void calculator_draw_callback(Canvas* canvas, void* ctx) { furi_assert(ctx); diff --git a/applications/external/doom/doom_music_player_worker.c b/applications/external/doom/doom_music_player_worker.c index e81549625..c8b9bb9db 100644 --- a/applications/external/doom/doom_music_player_worker.c +++ b/applications/external/doom/doom_music_player_worker.c @@ -393,7 +393,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { FURI_LOG_E(TAG, "Unable to open file"); break; - }; + } uint16_t ret = 0; do { diff --git a/applications/external/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/external/flipfrid/scene/flipfrid_scene_run_attack.c index 6c726832a..225752559 100644 --- a/applications/external/flipfrid/scene/flipfrid_scene_run_attack.c +++ b/applications/external/flipfrid/scene/flipfrid_scene_run_attack.c @@ -356,7 +356,7 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { stream_rewind(context->uids_stream); end_of_list = true; break; - }; + } if(furi_string_get_char(context->data_str, 0) == '#') continue; if(furi_string_size(context->data_str) != 11) break; break; @@ -370,7 +370,7 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_error); break; - }; + } // string is valid, parse it in context->payload for(uint8_t i = 0; i < 5; i++) { @@ -394,7 +394,7 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { stream_rewind(context->uids_stream); end_of_list = true; break; - }; + } if(furi_string_get_char(context->data_str, 0) == '#') continue; if(furi_string_size(context->data_str) != 9) break; break; @@ -408,7 +408,7 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_error); break; - }; + } // string is valid, parse it in context->payload for(uint8_t i = 0; i < 4; i++) { diff --git a/applications/external/hex_viewer/hex_viewer.c b/applications/external/hex_viewer/hex_viewer.c index 50c34d634..bd4afa1a8 100644 --- a/applications/external/hex_viewer/hex_viewer.c +++ b/applications/external/hex_viewer/hex_viewer.c @@ -163,7 +163,7 @@ static bool hex_viewer_open_file(HexViewer* hex_viewer, const char* file_path) { FURI_LOG_E(TAG, "Unable to open stream: %s", file_path); isOk = false; break; - }; + } hex_viewer->model->file_size = stream_size(hex_viewer->model->stream); } while(false); diff --git a/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c b/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c index 13ec6e6be..53f2f694f 100644 --- a/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c +++ b/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c @@ -242,7 +242,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { stream_rewind(context->uids_stream); end_of_list = true; break; - }; + } if(furi_string_get_char(context->data_str, 0) == '#') continue; if(furi_string_size(context->data_str) != 17) break; break; @@ -256,7 +256,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_error); break; - }; + } // string is valid, parse it in context->payload for(uint8_t i = 0; i < 8; i++) { @@ -280,7 +280,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { stream_rewind(context->uids_stream); end_of_list = true; break; - }; + } if(furi_string_get_char(context->data_str, 0) == '#') continue; if(furi_string_size(context->data_str) != 5) break; break; @@ -294,7 +294,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_error); break; - }; + } // string is valid, parse it in context->payload for(uint8_t i = 0; i < 2; i++) { @@ -318,7 +318,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { stream_rewind(context->uids_stream); end_of_list = true; break; - }; + } if(furi_string_get_char(context->data_str, 0) == '#') continue; if(furi_string_size(context->data_str) != 9) break; break; @@ -332,7 +332,7 @@ void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) { notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_error); break; - }; + } // string is valid, parse it in context->payload for(uint8_t i = 0; i < 4; i++) { diff --git a/applications/external/ifttt/ifttt_virtual_button.c b/applications/external/ifttt/ifttt_virtual_button.c index e23b8715d..9a0be7ef7 100644 --- a/applications/external/ifttt/ifttt_virtual_button.c +++ b/applications/external/ifttt/ifttt_virtual_button.c @@ -139,7 +139,7 @@ void send_serial_command_config(ESerialCommand command, Settings* settings) { break; default: return; - }; + } furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1); } diff --git a/applications/external/ifttt/views/send_view.c b/applications/external/ifttt/views/send_view.c index 6046c39e3..e1638e7a7 100644 --- a/applications/external/ifttt/views/send_view.c +++ b/applications/external/ifttt/views/send_view.c @@ -38,7 +38,7 @@ void send_serial_command_send(ESerialCommand command) { break; default: return; - }; + } furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1); } diff --git a/applications/external/metronome/metronome.c b/applications/external/metronome/metronome.c index a01f4418d..46231d66d 100644 --- a/applications/external/metronome/metronome.c +++ b/applications/external/metronome/metronome.c @@ -178,7 +178,7 @@ static void timer_callback(void* ctx) { case Silent: break; } - }; + } // this is a bit of a kludge... if we are on vibro and unpronounced, stop vibro after half the usual duration switch(metronome_state->output_mode) { diff --git a/applications/external/music_beeper/music_beeper_worker.c b/applications/external/music_beeper/music_beeper_worker.c index e06e77447..c95fe8d3a 100644 --- a/applications/external/music_beeper/music_beeper_worker.c +++ b/applications/external/music_beeper/music_beeper_worker.c @@ -399,7 +399,7 @@ bool music_beeper_worker_load_rtttl_from_file(MusicBeeperWorker* instance, const if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { FURI_LOG_E(TAG, "Unable to open file"); break; - }; + } uint16_t ret = 0; do { diff --git a/applications/external/music_player/music_player_worker.c b/applications/external/music_player/music_player_worker.c index ee350ee80..6a712d3e3 100644 --- a/applications/external/music_player/music_player_worker.c +++ b/applications/external/music_player/music_player_worker.c @@ -397,7 +397,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { FURI_LOG_E(TAG, "Unable to open file"); break; - }; + } uint16_t ret = 0; do { diff --git a/applications/external/picopass/rfal_picopass.c b/applications/external/picopass/rfal_picopass.c index ac66cb92d..e8ca64403 100644 --- a/applications/external/picopass/rfal_picopass.c +++ b/applications/external/picopass/rfal_picopass.c @@ -48,7 +48,7 @@ FuriHalNfcReturn rfalPicoPassPollerInitialize(void) { FuriHalNfcModePollPicopass, FuriHalNfcBitrate26p48, FuriHalNfcBitrate26p48); if(ret != FuriHalNfcReturnOk) { return ret; - }; + } furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_PICOPASS); diff --git a/applications/external/pocsag_pager/pocsag_pager_app_i.c b/applications/external/pocsag_pager/pocsag_pager_app_i.c index ff73ab50e..85e2a4bcf 100644 --- a/applications/external/pocsag_pager/pocsag_pager_app_i.c +++ b/applications/external/pocsag_pager/pocsag_pager_app_i.c @@ -131,7 +131,7 @@ void pcsg_hopper_update(POCSAGPagerApp* app) { if(app->txrx->txrx_state == PCSGTxRxStateRx) { pcsg_rx_end(app); - }; + } if(app->txrx->txrx_state == PCSGTxRxStateIDLE) { subghz_receiver_reset(app->txrx->receiver); app->txrx->preset->frequency = diff --git a/applications/external/pocsag_pager/scenes/pocsag_pager_receiver.c b/applications/external/pocsag_pager/scenes/pocsag_pager_receiver.c index 658b70fea..60dca01c9 100644 --- a/applications/external/pocsag_pager/scenes/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/scenes/pocsag_pager_receiver.c @@ -133,7 +133,7 @@ void pocsag_pager_scene_receiver_on_enter(void* context) { if(app->txrx->txrx_state == PCSGTxRxStateRx) { pcsg_rx_end(app); - }; + } if((app->txrx->txrx_state == PCSGTxRxStateIDLE) || (app->txrx->txrx_state == PCSGTxRxStateSleep)) { pcsg_begin( @@ -158,7 +158,7 @@ bool pocsag_pager_scene_receiver_on_event(void* context, SceneManagerEvent event if(app->txrx->txrx_state == PCSGTxRxStateRx) { pcsg_rx_end(app); pcsg_sleep(app); - }; + } app->txrx->hopper_state = PCSGHopperStateOFF; app->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(app->txrx->receiver, NULL, app); diff --git a/applications/external/pomodoro/flipp_pomodoro_app.c b/applications/external/pomodoro/flipp_pomodoro_app.c index 5adca1edb..718d18b00 100644 --- a/applications/external/pomodoro/flipp_pomodoro_app.c +++ b/applications/external/pomodoro/flipp_pomodoro_app.c @@ -9,14 +9,14 @@ static bool flipp_pomodoro_app_back_event_callback(void* ctx) { furi_assert(ctx); FlippPomodoroApp* app = ctx; return scene_manager_handle_back_event(app->scene_manager); -}; +} static void flipp_pomodoro_app_tick_event_callback(void* ctx) { furi_assert(ctx); FlippPomodoroApp* app = ctx; scene_manager_handle_custom_event(app->scene_manager, FlippPomodoroAppCustomEventTimerTick); -}; +} static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event) { furi_assert(ctx); @@ -40,7 +40,7 @@ static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event) break; } return scene_manager_handle_custom_event(app->scene_manager, event); -}; +} FlippPomodoroApp* flipp_pomodoro_app_alloc() { FlippPomodoroApp* app = malloc(sizeof(FlippPomodoroApp)); @@ -71,7 +71,7 @@ FlippPomodoroApp* flipp_pomodoro_app_alloc() { scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneTimer); return app; -}; +} void flipp_pomodoro_app_free(FlippPomodoroApp* app) { view_dispatcher_remove_view(app->view_dispatcher, FlippPomodoroAppViewTimer); @@ -81,7 +81,7 @@ void flipp_pomodoro_app_free(FlippPomodoroApp* app) { free(app); furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); -}; +} int32_t flipp_pomodoro_app(void* p) { UNUSED(p); @@ -92,4 +92,4 @@ int32_t flipp_pomodoro_app(void* p) { flipp_pomodoro_app_free(app); return 0; -}; +} diff --git a/applications/external/pomodoro/helpers/time.c b/applications/external/pomodoro/helpers/time.c index 7fb0d13c2..02540a939 100644 --- a/applications/external/pomodoro/helpers/time.c +++ b/applications/external/pomodoro/helpers/time.c @@ -7,7 +7,7 @@ const int TIME_MINUTES_IN_HOUR = 60; uint32_t time_now() { return furi_hal_rtc_get_timestamp(); -}; +} TimeDifference time_difference_seconds(uint32_t begin, uint32_t end) { const uint32_t duration_seconds = end - begin; @@ -17,4 +17,4 @@ TimeDifference time_difference_seconds(uint32_t begin, uint32_t end) { return ( TimeDifference){.total_seconds = duration_seconds, .minutes = minutes, .seconds = seconds}; -}; +} diff --git a/applications/external/pomodoro/modules/flipp_pomodoro.c b/applications/external/pomodoro/modules/flipp_pomodoro.c index 161e862f8..133db1eba 100644 --- a/applications/external/pomodoro/modules/flipp_pomodoro.c +++ b/applications/external/pomodoro/modules/flipp_pomodoro.c @@ -38,22 +38,22 @@ void flipp_pomodoro__toggle_stage(FlippPomodoroState* state) { furi_assert(state); state->current_stage_index = state->current_stage_index + 1; state->started_at_timestamp = time_now(); -}; +} PomodoroStage flipp_pomodoro__get_stage(FlippPomodoroState* state) { furi_assert(state); return flipp_pomodoro__stage_by_index(state->current_stage_index); -}; +} char* flipp_pomodoro__current_stage_label(FlippPomodoroState* state) { furi_assert(state); return current_stage_label[flipp_pomodoro__get_stage(state)]; -}; +} char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) { furi_assert(state); return next_stage_label[flipp_pomodoro__stage_by_index(state->current_stage_index + 1)]; -}; +} uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) { const int32_t stage_duration_seconds_map[] = { @@ -63,22 +63,22 @@ uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) }; return stage_duration_seconds_map[flipp_pomodoro__get_stage(state)]; -}; +} uint32_t flipp_pomodoro__stage_expires_timestamp(FlippPomodoroState* state) { return state->started_at_timestamp + flipp_pomodoro__current_stage_total_duration(state); -}; +} TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state) { const uint32_t stage_ends_at = flipp_pomodoro__stage_expires_timestamp(state); return time_difference_seconds(time_now(), stage_ends_at); -}; +} bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state) { const uint32_t expired_by = flipp_pomodoro__stage_expires_timestamp(state); const uint8_t seamless_change_span_seconds = 1; return (time_now() - seamless_change_span_seconds) >= expired_by; -}; +} FlippPomodoroState* flipp_pomodoro__new() { FlippPomodoroState* state = malloc(sizeof(FlippPomodoroState)); @@ -86,4 +86,4 @@ FlippPomodoroState* flipp_pomodoro__new() { state->started_at_timestamp = now; state->current_stage_index = 0; return state; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/applications/external/pomodoro/scenes/flipp_pomodoro_scene_timer.c b/applications/external/pomodoro/scenes/flipp_pomodoro_scene_timer.c index 2190dbdb7..8ed5dd5e7 100644 --- a/applications/external/pomodoro/scenes/flipp_pomodoro_scene_timer.c +++ b/applications/external/pomodoro/scenes/flipp_pomodoro_scene_timer.c @@ -15,7 +15,7 @@ void flipp_pomodoro_scene_timer_sync_view_state(void* ctx) { flipp_pomodoro_view_timer_set_state( flipp_pomodoro_view_timer_get_view(app->timer_view), app->state); -}; +} void flipp_pomodoro_scene_timer_on_next_stage(void* ctx) { furi_assert(ctx); @@ -23,7 +23,7 @@ void flipp_pomodoro_scene_timer_on_next_stage(void* ctx) { FlippPomodoroApp* app = ctx; view_dispatcher_send_custom_event(app->view_dispatcher, FlippPomodoroAppCustomEventStageSkip); -}; +} void flipp_pomodoro_scene_timer_on_enter(void* ctx) { furi_assert(ctx); @@ -34,7 +34,7 @@ void flipp_pomodoro_scene_timer_on_enter(void* ctx) { flipp_pomodoro_scene_timer_sync_view_state(app); flipp_pomodoro_view_timer_set_on_right_cb( app->timer_view, flipp_pomodoro_scene_timer_on_next_stage, app); -}; +} void flipp_pomodoro_scene_timer_handle_custom_event( FlippPomodoroApp* app, @@ -48,7 +48,7 @@ void flipp_pomodoro_scene_timer_handle_custom_event( if(custom_event == FlippPomodoroAppCustomEventStateUpdated) { flipp_pomodoro_scene_timer_sync_view_state(app); } -}; +} bool flipp_pomodoro_scene_timer_on_event(void* ctx, SceneManagerEvent event) { furi_assert(ctx); @@ -62,10 +62,10 @@ bool flipp_pomodoro_scene_timer_on_event(void* ctx, SceneManagerEvent event) { return ExitSignal; default: break; - }; + } return SceneEventNotConusmed; -}; +} void flipp_pomodoro_scene_timer_on_exit(void* ctx) { UNUSED(ctx); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/applications/external/pomodoro/views/flipp_pomodoro_timer_view.c b/applications/external/pomodoro/views/flipp_pomodoro_timer_view.c index e8e0383b7..302380ddd 100644 --- a/applications/external/pomodoro/views/flipp_pomodoro_timer_view.c +++ b/applications/external/pomodoro/views/flipp_pomodoro_timer_view.c @@ -58,7 +58,7 @@ static void remaining_stage_time_string); furi_string_free(timer_string); -}; +} static void draw_str_with_drop_shadow( Canvas* canvas, @@ -92,7 +92,7 @@ static void static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model) { if(!_model) { return; - }; + } FlippPomodoroTimerViewModel* model = _model; @@ -109,7 +109,7 @@ static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model canvas_set_font(canvas, FontSecondary); elements_button_right(canvas, flipp_pomodoro__next_stage_label(model->state)); -}; +} bool flipp_pomodoro_view_timer_input_callback(InputEvent* event, void* ctx) { furi_assert(ctx); @@ -125,15 +125,15 @@ bool flipp_pomodoro_view_timer_input_callback(InputEvent* event, void* ctx) { furi_assert(timer->right_cb_ctx); timer->right_cb(timer->right_cb_ctx); return ViewInputConsumed; - }; + } return ViewInputNotConusmed; -}; +} View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer) { furi_assert(timer); return timer->view; -}; +} void flipp_pomodoro_view_timer_assign_animation(View* view) { with_view_model( @@ -162,7 +162,7 @@ FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() { view_set_input_callback(timer->view, flipp_pomodoro_view_timer_input_callback); return timer; -}; +} void flipp_pomodoro_view_timer_set_on_right_cb( FlippPomodoroTimerView* timer, @@ -172,7 +172,7 @@ void flipp_pomodoro_view_timer_set_on_right_cb( furi_assert(right_cb_ctx); timer->right_cb = right_cb; timer->right_cb_ctx = right_cb_ctx; -}; +} void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state) { furi_assert(view); @@ -180,7 +180,7 @@ void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state) with_view_model( view, FlippPomodoroTimerViewModel * model, { model->state = state; }, false); flipp_pomodoro_view_timer_assign_animation(view); -}; +} void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer) { furi_assert(timer); @@ -192,4 +192,4 @@ void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer) { view_free(timer->view); free(timer); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c b/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c index 4c845b883..b73f2c448 100644 --- a/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c +++ b/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c @@ -63,7 +63,7 @@ static void draw_callback(Canvas* canvas, void* ctx) { elements_button_center(canvas, "New"); elements_button_left(canvas, notifications_enabled ? "On" : "Off"); -}; +} static void input_callback(InputEvent* input_event, void* ctx) { furi_assert(ctx); diff --git a/applications/external/sam/stm32_sam.cpp b/applications/external/sam/stm32_sam.cpp index 16f6fcaab..1ab73a66d 100644 --- a/applications/external/sam/stm32_sam.cpp +++ b/applications/external/sam/stm32_sam.cpp @@ -3945,7 +3945,7 @@ void STM32SAM::Code41240() { Insert(pos + 1, index + 1, phonemeLengthTable[index + 1], stress[pos]); Insert(pos + 2, index + 2, phonemeLengthTable[index + 2], stress[pos]); pos += 3; - }; + } } // Rewrites the phonemes using the following rules: diff --git a/applications/external/text_viewer/text_viewer.c b/applications/external/text_viewer/text_viewer.c index 59923adb9..b5ccb6ef3 100644 --- a/applications/external/text_viewer/text_viewer.c +++ b/applications/external/text_viewer/text_viewer.c @@ -157,7 +157,7 @@ static bool text_viewer_open_file(TextViewer* text_viewer, const char* file_path FURI_LOG_E(TAG, "Unable to open stream: %s", file_path); isOk = false; break; - }; + } text_viewer->model->file_size = stream_size(text_viewer->model->stream); } while(false); diff --git a/applications/external/totp/lib/roll_value/roll_value.c b/applications/external/totp/lib/roll_value/roll_value.c index 326c7846a..563429d0d 100644 --- a/applications/external/totp/lib/roll_value/roll_value.c +++ b/applications/external/totp/lib/roll_value/roll_value.c @@ -25,4 +25,4 @@ TOTP_ROLL_VALUE_FN(int8_t, int8_t) TOTP_ROLL_VALUE_FN(uint8_t, int8_t) -TOTP_ROLL_VALUE_FN(size_t, int16_t); \ No newline at end of file +TOTP_ROLL_VALUE_FN(size_t, int16_t) \ No newline at end of file diff --git a/applications/external/wav_player/wav_parser.c b/applications/external/wav_player/wav_parser.c index 1f534bacb..8c1f22b19 100644 --- a/applications/external/wav_player/wav_parser.c +++ b/applications/external/wav_player/wav_parser.c @@ -11,7 +11,7 @@ const char* format_text(FormatTag tag) { default: return "Unknown"; } -}; +} struct WavParser { WavHeaderChunk header; diff --git a/applications/external/weather_station/scenes/weather_station_receiver.c b/applications/external/weather_station/scenes/weather_station_receiver.c index e76810430..79d01f13d 100644 --- a/applications/external/weather_station/scenes/weather_station_receiver.c +++ b/applications/external/weather_station/scenes/weather_station_receiver.c @@ -133,7 +133,7 @@ void weather_station_scene_receiver_on_enter(void* context) { if(app->txrx->txrx_state == WSTxRxStateRx) { ws_rx_end(app); - }; + } if((app->txrx->txrx_state == WSTxRxStateIDLE) || (app->txrx->txrx_state == WSTxRxStateSleep)) { ws_begin( app, @@ -157,7 +157,7 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev if(app->txrx->txrx_state == WSTxRxStateRx) { ws_rx_end(app); ws_sleep(app); - }; + } app->txrx->hopper_state = WSHopperStateOFF; app->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(app->txrx->receiver, NULL, app); diff --git a/applications/external/weather_station/weather_station_app_i.c b/applications/external/weather_station/weather_station_app_i.c index 7236b6625..2e83a6e30 100644 --- a/applications/external/weather_station/weather_station_app_i.c +++ b/applications/external/weather_station/weather_station_app_i.c @@ -146,7 +146,7 @@ void ws_hopper_update(WeatherStationApp* app) { if(app->txrx->txrx_state == WSTxRxStateRx) { ws_rx_end(app); - }; + } if(app->txrx->txrx_state == WSTxRxStateIDLE) { subghz_receiver_reset(app->txrx->receiver); app->txrx->preset->frequency = diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index 87eafaecd..2a06e348c 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -258,7 +258,7 @@ int32_t fap_loader_app(char* p) { if(fap_loader_run_selected_app(loader, false)) { fap_loader_run_selected_app(loader, true); } - }; + } } fap_loader_free(loader); diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index 54bc808b5..12da64fcc 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -31,7 +31,7 @@ static void ibutton_cli_print_usage() { printf("\tCyfral (2 bytes key_data)\r\n"); printf("\tMetakom (4 bytes key_data), must contain correct parity\r\n"); printf("\t are hex-formatted\r\n"); -}; +} static bool ibutton_cli_parse_key(iButtonProtocols* protocols, iButtonKey* key, FuriString* args) { bool result = false; @@ -124,7 +124,7 @@ static void ibutton_cli_read(Cli* cli) { ibutton_protocols_free(protocols); furi_event_flag_free(event); -}; +} typedef struct { FuriEventFlag* event; @@ -216,7 +216,7 @@ void ibutton_cli_emulate(Cli* cli, FuriString* args) { while(!cli_cmd_interrupt_received(cli)) { furi_delay_ms(100); - }; + } } while(false); @@ -226,7 +226,7 @@ void ibutton_cli_emulate(Cli* cli, FuriString* args) { ibutton_key_free(key); ibutton_worker_free(worker); ibutton_protocols_free(protocols); -}; +} void ibutton_cli(Cli* cli, FuriString* args, void* context) { UNUSED(cli); diff --git a/applications/main/lfrfid/lfrfid_cli.c b/applications/main/lfrfid/lfrfid_cli.c index a57e40de9..cc1fa2bd7 100644 --- a/applications/main/lfrfid/lfrfid_cli.c +++ b/applications/main/lfrfid/lfrfid_cli.c @@ -30,7 +30,7 @@ static void lfrfid_cli_print_usage() { printf("rfid raw_read \r\n"); printf("rfid raw_emulate \r\n"); printf("rfid raw_analyze \r\n"); -}; +} typedef struct { ProtocolId protocol; diff --git a/applications/main/onewire/onewire_cli.c b/applications/main/onewire/onewire_cli.c index 5f6cdc670..9a7ffe55c 100644 --- a/applications/main/onewire/onewire_cli.c +++ b/applications/main/onewire/onewire_cli.c @@ -21,7 +21,7 @@ void onewire_on_system_start() { static void onewire_cli_print_usage() { printf("Usage:\r\n"); printf("onewire search\r\n"); -}; +} static void onewire_cli_search(Cli* cli) { UNUSED(cli); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 2638d2089..5734a8e9f 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -152,7 +152,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); - }; + } //Stop save file subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -196,7 +196,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); - }; + } subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -305,7 +305,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); - }; + } size_t spl_count = subghz_protocol_raw_get_sample_write( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -439,7 +439,7 @@ void subghz_scene_read_raw_on_exit(void* context) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); - }; + } subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index dd0160213..cbef8fe97 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -603,7 +603,7 @@ void subghz_hopper_update(SubGhz* subghz) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); - }; + } if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { subghz_receiver_reset(subghz->txrx->receiver); subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency( diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index a8d1b7e67..a652d0f0c 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -79,7 +79,7 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) { printf("%s", furi_string_get_cstr(*CliCommandTree_ref(it_right)->key_ptr)); CliCommandTree_next(it_right); } - }; + } if(furi_string_size(args) > 0) { cli_nl(); diff --git a/applications/services/crypto/crypto_cli.c b/applications/services/crypto/crypto_cli.c index d91b448ec..34aa34dd3 100644 --- a/applications/services/crypto/crypto_cli.c +++ b/applications/services/crypto/crypto_cli.c @@ -15,7 +15,7 @@ void crypto_cli_print_usage() { printf("\thas_key \t - Check if secure enclave has key in slot\r\n"); printf( "\tstore_key \t - Store key in secure enclave. !!! NON-REVERSIBLE OPERATION - READ MANUAL FIRST !!!\r\n"); -}; +} void crypto_cli_encrypt(Cli* cli, FuriString* args) { int key_slot = 0; diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 190efa5ec..fba3c5a90 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -101,7 +101,7 @@ bool dolphin_state_is_levelup(int icounter) { if((icounter == DOLPHIN_LEVELS[i])) { return true; } - }; + } return false; } diff --git a/applications/services/gui/modules/popup.c b/applications/services/gui/modules/popup.c index d75abb95f..ad26b2691 100644 --- a/applications/services/gui/modules/popup.c +++ b/applications/services/gui/modules/popup.c @@ -99,7 +99,7 @@ void popup_start_timer(void* context) { if(furi_timer_start(popup->timer, timer_period) != FuriStatusOk) { furi_assert(0); - }; + } } } diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 01ccdbf52..6dc558815 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -85,7 +85,7 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { // Set text position to 5th line from the end for(uint8_t i = 0; i < line_num - 5; i++) { while(*model->text_pos++ != '\n') { - }; + } } model->scroll_num = line_num - 4; model->scroll_pos = line_num - 5; diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index a26d84ab3..76dc2e052 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -36,7 +36,7 @@ void notification_message_save_settings(NotificationApp* app) { furi_event_flag_wait( m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_event_flag_free(m.back_event); -}; +} // internal layer void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) { @@ -336,7 +336,7 @@ void notification_process_notification_message( } notification_message_index++; notification_message = (*message->sequence)[notification_message_index]; - }; + } // send and do minimal delay if(led_active) { @@ -447,7 +447,7 @@ static bool notification_load_settings(NotificationApp* app) { furi_record_close(RECORD_STORAGE); return fs_result; -}; +} static bool notification_save_settings(NotificationApp* app) { NotificationSettings settings; @@ -482,7 +482,7 @@ static bool notification_save_settings(NotificationApp* app) { furi_record_close(RECORD_STORAGE); return fs_result; -}; +} static void input_event_callback(const void* value, void* context) { furi_assert(value); @@ -531,7 +531,7 @@ static NotificationApp* notification_app_alloc() { notification_message(app, &sequence_display_backlight_on); return app; -}; +} // App int32_t notification_srv(void* p) { diff --git a/applications/services/notification/notification_app_api.c b/applications/services/notification/notification_app_api.c index 9bc06b013..9bcf5964f 100644 --- a/applications/services/notification/notification_app_api.c +++ b/applications/services/notification/notification_app_api.c @@ -8,13 +8,13 @@ void notification_message(NotificationApp* app, const NotificationSequence* sequ NotificationAppMessage m = { .type = NotificationLayerMessage, .sequence = sequence, .back_event = NULL}; furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); -}; +} void notification_internal_message(NotificationApp* app, const NotificationSequence* sequence) { NotificationAppMessage m = { .type = InternalLayerMessage, .sequence = sequence, .back_event = NULL}; furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); -}; +} void notification_message_block(NotificationApp* app, const NotificationSequence* sequence) { NotificationAppMessage m = { @@ -25,7 +25,7 @@ void notification_message_block(NotificationApp* app, const NotificationSequence furi_event_flag_wait( m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_event_flag_free(m.back_event); -}; +} void notification_internal_message_block( NotificationApp* app, @@ -36,4 +36,4 @@ void notification_internal_message_block( furi_event_flag_wait( m.back_event, NOTIFICATION_EVENT_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_event_flag_free(m.back_event); -}; +} diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/applications/services/rgb_backlight/rgb_backlight.c index 2dbfa7e8c..9b39b469a 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/applications/services/rgb_backlight/rgb_backlight.c @@ -103,7 +103,7 @@ void rgb_backlight_load_settings(void) { storage_file_free(file); furi_record_close(RECORD_STORAGE); rgb_settings.settings_is_loaded = true; -}; +} void rgb_backlight_save_settings(void) { RGBBacklightSettings settings; @@ -134,7 +134,7 @@ void rgb_backlight_save_settings(void) { storage_file_close(file); storage_file_free(file); furi_record_close(RECORD_STORAGE); -}; +} RGBBacklightSettings* rgb_backlight_get_settings(void) { if(!rgb_settings.settings_is_loaded) { diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 8e2dcdbbb..d720de9d1 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -33,7 +33,7 @@ static void storage_cli_print_usage() { printf("\tmd5\t - md5 hash of the file\r\n"); printf("\tstat\t - info about file or dir\r\n"); printf("\ttimestamp\t - last modification timestamp\r\n"); -}; +} static void storage_cli_print_error(FS_Error error) { printf("Storage error: %s\r\n", storage_error_get_desc(error)); @@ -86,7 +86,7 @@ static void storage_cli_info(Cli* cli, FuriString* path) { } furi_record_close(RECORD_STORAGE); -}; +} static void storage_cli_format(Cli* cli, FuriString* path) { if(furi_string_cmp_str(path, STORAGE_INT_PATH_PREFIX) == 0) { @@ -112,7 +112,7 @@ static void storage_cli_format(Cli* cli, FuriString* path) { } else { storage_cli_print_usage(); } -}; +} static void storage_cli_list(Cli* cli, FuriString* path) { UNUSED(cli); diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index c1cf2c7de..8e4e2b0fc 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -160,7 +160,7 @@ static LFSData* storage_int_lfs_data_alloc() { lfs_data->config.lookahead_size = 16; return lfs_data; -}; +} // Returns true if fingerprint was invalid and LFS reformatting is needed static bool storage_int_check_and_set_fingerprint(LFSData* lfs_data) { diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 20263e887..2f61ceb2c 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -179,7 +179,7 @@ static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) canvas_draw_box(canvas, x - 4, y + 16, 24, 6); canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); -}; +} static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { char header[20] = {}; @@ -245,7 +245,7 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { canvas_draw_str_aligned(canvas, x + 92, y + 9, AlignCenter, AlignCenter, header); canvas_draw_str_aligned(canvas, x + 92, y + 19, AlignCenter, AlignCenter, value); } -}; +} static void battery_info_draw_callback(Canvas* canvas, void* context) { furi_assert(context); diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 0956cae4f..828c518d6 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -18,7 +18,7 @@ static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) canvas_draw_box(canvas, x - 4, y + 16, 24, 6); canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); -}; +} static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { char emote[20] = {}; @@ -87,7 +87,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value); -}; +} static void battery_info_draw_callback(Canvas* canvas, void* context) { furi_assert(context); From e8a1718b8eb9de0c4ee7243f3ad0b977c77d6321 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 17:53:54 +0100 Subject: [PATCH 086/216] Update apps --- .../external/asteroids/application.fam | 2 +- .../external/bpmtapper/img/screenshot.png | Bin 1987 -> 0 bytes .../brainfuck/icons/DolphinCommon_56x48.png | Bin 1416 -> 0 bytes .../external/brainfuck/icons/Text_10x10.png | Bin 158 -> 0 bytes .../external/cli_bridge/internal_defs.h | 4 +- .../external/doom/assets/screenshot1.png | Bin 1487 -> 0 bytes .../external/doom/assets/screenshot2.png | Bin 1705 -> 0 bytes .../external/doom/assets/screenshot3.png | Bin 1629 -> 0 bytes applications/external/geiger/flipper_geiger.c | 59 +++++++++----- .../GPIO_reader.c | 0 .../GPIO_reader_item.c | 0 .../GPIO_reader_item.h | 0 .../application.fam | 0 .../{gpio_reader_a => gpioreader_a}/icon.png | Bin .../{gpio_reader_b => gpioreader_b}/LICENSE | 0 .../application.fam | 0 .../gpio_app.c | 0 .../gpio_app.h | 0 .../gpio_app_i.h | 0 .../gpio_custom_event.h | 0 .../gpio_item.c | 0 .../gpio_item.h | 0 .../{gpio_reader_b => gpioreader_b}/icon.png | Bin .../scenes/gpio_scene.c | 0 .../scenes/gpio_scene.h | 0 .../scenes/gpio_scene_config.h | 0 .../scenes/gpio_scene_reader.c | 0 .../scenes/gpio_scene_start.c | 0 .../scenes/gpio_scene_test.c | 0 .../scenes/gpio_scene_usb_uart.c | 0 .../scenes/gpio_scene_usb_uart_close_rpc.c | 0 .../scenes/gpio_scene_usb_uart_config.c | 0 .../usb_uart_bridge.c | 0 .../usb_uart_bridge.h | 0 .../views/gpio_reader.c | 0 .../views/gpio_reader.h | 0 .../views/gpio_test.c | 0 .../views/gpio_test.h | 0 .../views/gpio_usb_uart.c | 2 +- .../views/gpio_usb_uart.h | 0 .../external/metronome/img/screenshot.png | Bin 1978 -> 0 bytes .../external/minesweeper/img/screenshot.png | Bin 1842 -> 0 bytes .../application.fam | 1 + .../tracker_engine/speaker_hal.c | 11 +-- .../tracker_engine/speaker_hal.h | 0 .../tracker_engine/tracker.c | 0 .../tracker_engine/tracker.h | 0 .../tracker_engine/tracker_notes.h | 0 .../tracker_engine/tracker_song.h | 0 .../view/tracker_view.c | 0 .../view/tracker_view.h | 0 .../zero_tracker.c | 0 .../zero_tracker.h | 0 .../zero_tracker.png | Bin .../application.fam | 0 .../clock.png | Bin .../clock_app.c | 0 .../clock_app.h | 0 .../external/pomodoro/flipp_pomodoro_app.c | 1 + .../pomodoro/modules/flipp_pomodoro.c | 5 ++ applications/external/pong/flipper_pong.c | 30 +++---- applications/external/rc2014_coleco/coleco.c | 22 +++--- .../rubiks_cube_scrambler.c | 35 ++++----- .../rubiks_cube_scrambler/scrambler.c | 74 ++++-------------- .../rubiks_cube_scrambler/scrambler.h | 1 - .../timelapse/icons/ButtonDownHollow_7x4.png | Bin 0 -> 173 bytes .../timelapse/icons/ButtonLeftHollow_4x7.png | Bin 0 -> 149 bytes .../timelapse/icons/ButtonRightHollow_4x7.png | Bin 0 -> 147 bytes .../timelapse/icons/ButtonUpHollow_7x4.png | Bin 0 -> 143 bytes applications/external/timelapse/zeitraffer.c | 32 +++++--- .../external/{wii_ec_anal => wiiec}/LICENSE | 0 .../external/{wii_ec_anal => wiiec}/WiiEC.png | Bin .../_image_tool/LICENSE | 0 .../{wii_ec_anal => wiiec}/_image_tool/README | 0 .../_image_tool/_convert.c | 0 .../_image_tool/_convert.sh | 0 .../_image_tool/_convert_images.c | 0 .../_image_tool/_convert_images.h | 0 .../_image_tool/_convert_test.c | 0 .../{wii_ec_anal => wiiec}/application.fam | 0 .../{wii_ec_anal => wiiec}/bc_logging.h | 0 .../external/{wii_ec_anal => wiiec}/err.h | 0 .../{wii_ec_anal => wiiec}/gfx/images.c | 0 .../{wii_ec_anal => wiiec}/gfx/images.h | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_0.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_1.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_2.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_3.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_4.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_5.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_6.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_7.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_8.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_9.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_3x5_v.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_0.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_1.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_2.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_3.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_4.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_5.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_6.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_7.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_8.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_9.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_A.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_B.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_C.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_D.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_E.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_5x7_F.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_0.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_1.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_2.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_3.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_4.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_5.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_6.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_7.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_8.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_9.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_A.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_B.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_C.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_D.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_E.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_F.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_G.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_X.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_Y.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_Z.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_d_.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_n_.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_6x8_v_.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_RIP.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_cc_Cable.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_cc_Joy.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_cc_Main.c | 0 .../gfx/img_cc_btn_A1.c | 0 .../gfx/img_cc_btn_B1.c | 0 .../gfx/img_cc_btn_X1.c | 0 .../gfx/img_cc_btn_Y1.c | 0 .../gfx/img_cc_pad_LR1.c | 0 .../gfx/img_cc_pad_UD1.c | 0 .../gfx/img_cc_trg_L1.c | 0 .../gfx/img_cc_trg_L2.c | 0 .../gfx/img_cc_trg_L3.c | 0 .../gfx/img_cc_trg_L4.c | 0 .../gfx/img_cc_trg_R1.c | 0 .../gfx/img_cc_trg_R2.c | 0 .../gfx/img_cc_trg_R3.c | 0 .../gfx/img_cc_trg_R4.c | 0 .../gfx/img_csLogo_FULL.c | 0 .../gfx/img_csLogo_Small.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_ecp_SCL.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_ecp_SDA.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_ecp_port.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_Back.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_D.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_L.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_OK.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_OKi.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_R.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_U.c | 0 .../{wii_ec_anal => wiiec}/gfx/img_key_Ui.c | 0 .../{wii_ec_anal => wiiec}/i2c_workaround.h | 0 .../external/{wii_ec_anal => wiiec}/info.sh | 0 .../{wii_ec_anal => wiiec}/wii_anal.c | 25 ++++-- .../{wii_ec_anal => wiiec}/wii_anal.h | 3 +- .../{wii_ec_anal => wiiec}/wii_anal_ec.c | 0 .../{wii_ec_anal => wiiec}/wii_anal_ec.h | 0 .../{wii_ec_anal => wiiec}/wii_anal_keys.c | 0 .../{wii_ec_anal => wiiec}/wii_anal_keys.h | 0 .../{wii_ec_anal => wiiec}/wii_anal_lcd.c | 0 .../{wii_ec_anal => wiiec}/wii_anal_lcd.h | 0 .../{wii_ec_anal => wiiec}/wii_anal_ver.h | 1 + .../external/{wii_ec_anal => wiiec}/wii_ec.c | 0 .../external/{wii_ec_anal => wiiec}/wii_ec.h | 0 .../{wii_ec_anal => wiiec}/wii_ec_classic.c | 0 .../{wii_ec_anal => wiiec}/wii_ec_classic.h | 0 .../{wii_ec_anal => wiiec}/wii_ec_macros.h | 0 .../{wii_ec_anal => wiiec}/wii_ec_nunchuck.c | 0 .../{wii_ec_anal => wiiec}/wii_ec_nunchuck.h | 0 .../{wii_ec_anal => wiiec}/wii_ec_udraw.c | 0 .../{wii_ec_anal => wiiec}/wii_ec_udraw.h | 0 .../external/{wii_ec_anal => wiiec}/wii_i2c.c | 0 .../external/{wii_ec_anal => wiiec}/wii_i2c.h | 0 187 files changed, 149 insertions(+), 159 deletions(-) delete mode 100644 applications/external/bpmtapper/img/screenshot.png delete mode 100644 applications/external/brainfuck/icons/DolphinCommon_56x48.png delete mode 100644 applications/external/brainfuck/icons/Text_10x10.png delete mode 100644 applications/external/doom/assets/screenshot1.png delete mode 100644 applications/external/doom/assets/screenshot2.png delete mode 100644 applications/external/doom/assets/screenshot3.png rename applications/external/{gpio_reader_a => gpioreader_a}/GPIO_reader.c (100%) rename applications/external/{gpio_reader_a => gpioreader_a}/GPIO_reader_item.c (100%) rename applications/external/{gpio_reader_a => gpioreader_a}/GPIO_reader_item.h (100%) rename applications/external/{gpio_reader_a => gpioreader_a}/application.fam (100%) rename applications/external/{gpio_reader_a => gpioreader_a}/icon.png (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/LICENSE (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/application.fam (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_app.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_app.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_app_i.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_custom_event.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_item.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/gpio_item.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/icon.png (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_config.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_reader.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_start.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_test.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_usb_uart.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_usb_uart_close_rpc.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/scenes/gpio_scene_usb_uart_config.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/usb_uart_bridge.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/usb_uart_bridge.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_reader.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_reader.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_test.c (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_test.h (100%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_usb_uart.c (98%) rename applications/external/{gpio_reader_b => gpioreader_b}/views/gpio_usb_uart.h (100%) delete mode 100644 applications/external/metronome/img/screenshot.png delete mode 100644 applications/external/minesweeper/img/screenshot.png rename applications/external/{musictracker => music_tracker}/application.fam (90%) rename applications/external/{musictracker => music_tracker}/tracker_engine/speaker_hal.c (91%) rename applications/external/{musictracker => music_tracker}/tracker_engine/speaker_hal.h (100%) rename applications/external/{musictracker => music_tracker}/tracker_engine/tracker.c (100%) rename applications/external/{musictracker => music_tracker}/tracker_engine/tracker.h (100%) rename applications/external/{musictracker => music_tracker}/tracker_engine/tracker_notes.h (100%) rename applications/external/{musictracker => music_tracker}/tracker_engine/tracker_song.h (100%) rename applications/external/{musictracker => music_tracker}/view/tracker_view.c (100%) rename applications/external/{musictracker => music_tracker}/view/tracker_view.h (100%) rename applications/external/{musictracker => music_tracker}/zero_tracker.c (100%) rename applications/external/{musictracker => music_tracker}/zero_tracker.h (100%) rename applications/external/{musictracker => music_tracker}/zero_tracker.png (100%) rename applications/external/{nightstand_clock => nightstand}/application.fam (100%) rename applications/external/{nightstand_clock => nightstand}/clock.png (100%) rename applications/external/{nightstand_clock => nightstand}/clock_app.c (100%) rename applications/external/{nightstand_clock => nightstand}/clock_app.h (100%) create mode 100644 applications/external/timelapse/icons/ButtonDownHollow_7x4.png create mode 100644 applications/external/timelapse/icons/ButtonLeftHollow_4x7.png create mode 100644 applications/external/timelapse/icons/ButtonRightHollow_4x7.png create mode 100644 applications/external/timelapse/icons/ButtonUpHollow_7x4.png rename applications/external/{wii_ec_anal => wiiec}/LICENSE (100%) rename applications/external/{wii_ec_anal => wiiec}/WiiEC.png (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/LICENSE (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/README (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/_convert.c (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/_convert.sh (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/_convert_images.c (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/_convert_images.h (100%) rename applications/external/{wii_ec_anal => wiiec}/_image_tool/_convert_test.c (100%) rename applications/external/{wii_ec_anal => wiiec}/application.fam (100%) rename applications/external/{wii_ec_anal => wiiec}/bc_logging.h (100%) rename applications/external/{wii_ec_anal => wiiec}/err.h (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/images.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/images.h (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_0.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_2.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_3.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_4.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_5.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_6.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_7.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_8.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_9.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_3x5_v.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_0.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_2.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_3.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_4.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_5.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_6.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_7.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_8.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_9.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_A.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_B.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_C.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_D.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_E.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_5x7_F.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_0.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_2.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_3.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_4.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_5.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_6.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_7.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_8.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_9.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_A.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_B.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_C.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_D.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_E.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_F.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_G.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_X.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_Y.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_Z.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_d_.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_n_.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_6x8_v_.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_RIP.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_Cable.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_Joy.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_Main.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_btn_A1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_btn_B1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_btn_X1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_btn_Y1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_pad_LR1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_pad_UD1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_L1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_L2.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_L3.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_L4.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_R1.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_R2.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_R3.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_cc_trg_R4.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_csLogo_FULL.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_csLogo_Small.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_ecp_SCL.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_ecp_SDA.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_ecp_port.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_Back.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_D.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_L.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_OK.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_OKi.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_R.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_U.c (100%) rename applications/external/{wii_ec_anal => wiiec}/gfx/img_key_Ui.c (100%) rename applications/external/{wii_ec_anal => wiiec}/i2c_workaround.h (100%) rename applications/external/{wii_ec_anal => wiiec}/info.sh (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal.c (96%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal.h (98%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_ec.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_ec.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_keys.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_keys.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_lcd.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_lcd.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_anal_ver.h (85%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_classic.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_classic.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_macros.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_nunchuck.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_nunchuck.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_udraw.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_ec_udraw.h (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_i2c.c (100%) rename applications/external/{wii_ec_anal => wiiec}/wii_i2c.h (100%) diff --git a/applications/external/asteroids/application.fam b/applications/external/asteroids/application.fam index 5f70a0e1c..5eb43a6e5 100644 --- a/applications/external/asteroids/application.fam +++ b/applications/external/asteroids/application.fam @@ -8,8 +8,8 @@ App( stack_size=8 * 1024, order=50, fap_icon="appicon.png", - fap_icon_assets="assets", # Image assets to compile for this application fap_category="Games", + fap_icon_assets="assets", # Image assets to compile for this application fap_description="An implementation of the classic arcade game Asteroids", fap_author="antirez, SimplyMinimal", fap_weburl="https://github.com/SimplyMinimal/FlipperZero-Asteroids", diff --git a/applications/external/bpmtapper/img/screenshot.png b/applications/external/bpmtapper/img/screenshot.png deleted file mode 100644 index fbba2aad9026c40fd85788ed73ff4279b825cff0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1987 zcmd6odrVVT9LG;VMd}pe#uOzmmpGkOqBfum3r-n`Tfq8&ImJqd)U+y$4q94hL543L zH3sIa(7JU3N*}O_6``$*NEa+tx?t0AB7_6j(SH_E-*WatGgx-G?XuENPv4P!*UZs{ruH zii`gI0IhOtD7maE=7XZn?;bsvoZh~Wt$x{HxpeNxr>hI9(H9*;=tT0a$u8|@HP@%7 zol}lrV9g!I0bpJYz|Zr*j&cCbF9QJY1wPsXKy+Tj6fcT3vvSMA@sD#mxKoO()9ND; z8nObbInVGHRiWRe`GWjfb^uNw9PaOO9LMxgPRCZUG?QdeOH9eZ=Ir$#e;o=eUE|&& zUgooDpjJN^3yr63r?PIRPq#*<{?=)1&Pw1mrL)UYY|a)fZF;T0N6MoP)JbTElu5C| z5{8)3CfOqEhVN+S@@yum5l;BU>mSXerto~66ULMpd>@JACjB7&kifc(|a@y3Q8c^6|1 zLR&CZIEf=g@P~bA?OO}ff#UI-N7LIlVX?CzX}N{e#!1!PbFo#tiklvHIa_?{z4A_R zPmDlkXi*4j1oP)D>V)-s5JPUaGDajeu5p&*FX{|R68TZmwok+#@H8mLFaLEK%jd2e?SdNg^r3ZKH622T}j7VeDxy93?4e6yRY8%^9_KL2{`66C;wm*hfi+tQA>3*2K(*Yn^c#BY zkT|XKTo1j=y;QN@*>o9!no@-dO!mtw3O#tIt)58W_i_|ZYbkPVw#eGLdFlva$4Ki^ z6bE6K8`Qr^{5S0XyUDy}2ACO}Qi@qlSQn*87;>GARYs92`Hu(otK_UQGhC~MzA5lH zvyK8bq_oYn8pEI~%1qgC;X6~yn~VW7II}@&4qwY3UQMI3a*7;Eh>nC%g{rT_;&htX z=AF8h`w%?@LDVY{@@q{3J;~21f(CIqnXVo7Q{V8A&>jdL24II-34p0y3~!;L_7*a|J9u1OY(0B z2VvdH!zn>8L~zuKFFpTjd3gS%8moZU2kYz|Bz^W-yz)fIbNV~WX51p;ZlyP8>UcR; z=Qu*VVHY8b+ibta5WO}v2sfSGDB&Gu*(sCM4)3Y}Zvr1tCIjHHy%aHYimZ&dHkE@z zSTyVn&hPW6ojdXVYtEoCGpeOf9jtJ{TNNxOfkdE|zEOqoXeLJ6#659;>VU+_cVx{* zUGczC%ihT&pA`nZ;4;mflt>bxt~94RJ2AqBE3;isS~1WLKP9Cy(TGAXz@W?q*=Ahr z+-LjkY$A8F&QhMLOYL?nO~7w!tJ&`{q2fpHKKf($wXr}jp|V^JJry$s_w+Ud%X|{$ zW~{*G^3m*lCz}?^7-C}>*BN%LM02sJPRg+Mu|?k4m#Y>OG409lA3?-dUb+f|{K3Hc zT&Av*Ir2WEksmn56FpgUw4Y>jDeADgt<1Fu0+vw#QSOuRs>y;+H1?Enmgi{FZ*z8O z#WU2~UdZ~w^D!OMZTD*%O}x9GFyHhgxsE=p&`WatkXMKyA-7b%xiWJA<-V0c+!yiD JqMgUi{0T658(RPX diff --git a/applications/external/brainfuck/icons/DolphinCommon_56x48.png b/applications/external/brainfuck/icons/DolphinCommon_56x48.png deleted file mode 100644 index 089aaed83507431993a76ca25d32fdd9664c1c84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1416 zcmaJ>eNYr-7(dh;KXS5&nWVIBjS_NizYg|x=Pr^vz*7zxJO|P-dw2IeZq?gec9-rD zoPZchQ_6}yP{Slc4I!!28K==nodOJ_nsCY-(wOq2uZbLx!rlYU{KIi)_Wj!D_j`WN z^FGgREXdEDF)ewT&1Re7Tj(uBvlG44lnH3;I%IzsO|z`*Vr!`uv?9QOwgs{#Ld+Ki zC9n_zxxBOkx@@+IwMwAaD)#3Ik`}gun2kLe))Crfb7e+#AgzHGCc+X$b>qJuIf`S7 z?8b}I{ghw#z>uiaLknQh@LJUrqHcVYS3v97F^OZN zCe|7^J|?QzUx0Zu17e(=CM1fYFpjtLk|a4~$g}e?hGH0!VoBOT&<=s(1ct%J9~?O} z$)jW_dkX9yTX~%W*i_IM%0{ z7EmP^_pKn`<5>E(SixgJU};7`)7Hidp&+DLnizsebUk}_-GfgbN^il9b`v)f+ z{o5Zry)d<7`fHQ^uw_;+x>mcPw0&8iW69x{k92O{Q}`yFdH=5d$pbf49w1&NS)G+vhr6y}5TMsofQirRDUmKilk5=(KGouJ{H9hW=$X zgi;)vI!jl!_4H3jD(?Jz=8By|i47I&tKA1y9{nfp;_|FxKBDNWp{hN9hJ1nU?z%J6 z?>UxyzWvO}Pgc~rCZ#5%Eq+_hNS~bBdiGlT&f%%e`hHjSySR2=JuK2^+%;$R3#Wz~ z=e_mfqW23bPa0fhe)HdE5+GelU&!jS3ckUZOQ)CC5?mo zo=tzG_4|RuvPUO|mhCwA>y)1c%SWC%a4?a-x|J*?ch~+n=R7o@>p6J2dE=$stKZmK z-xoTRwET2^Wu)&1U7!Ebw!!D?x`xwQX3pMnrRwCT?`4GHt4&?|cIiI{_^XYp-np>6 xE^lPSXzOYCC4X`6tl@OB1M5_S7jml-Y~(TPp{aTIejNKZ`m*!Atyxdk{0EAy49frj diff --git a/applications/external/brainfuck/icons/Text_10x10.png b/applications/external/brainfuck/icons/Text_10x10.png deleted file mode 100644 index 8e8a6183dd50535729dc9c9b4f220a12dd4c600f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2VGmzZ%#=aj&u?6^qxB}__|Nk$&IsYz@rRC}3 z7*a7OIiZ2U&CSi=;0cBn1vTatM&Z;3u7g(^G9`qQn09G2aWeNXaKC0S=Q~tg57Z@F z;u=vBoS#-wo>-L1;E+?AmspUPnOCA;ke9BToS%}K{MA`f4ycg9)78&qol`;+00Iau A9smFU diff --git a/applications/external/cli_bridge/internal_defs.h b/applications/external/cli_bridge/internal_defs.h index 9840d008b..09fe6169c 100644 --- a/applications/external/cli_bridge/internal_defs.h +++ b/applications/external/cli_bridge/internal_defs.h @@ -79,8 +79,8 @@ typedef struct { void* view_dispatcher; void* primary_menu; - void* plugins_menu; - void* debug_menu; + // void* plugins_menu; + // void* debug_menu; void* settings_menu; volatile uint8_t lock_count; diff --git a/applications/external/doom/assets/screenshot1.png b/applications/external/doom/assets/screenshot1.png deleted file mode 100644 index 1ecb073a69f3692705a6b5a76947d7ceb6dfab3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1487 zcmeAS@N?(olHy`uVBq!ia0y~yU;;8388|?c*QZDWAjMhW5n0T@z;^_M8K-LVNi#68 zHhQ`^hE&XXdpEZ4vK2!^pjDFPnts;}cGsHUNv|pqJ$dkF@&4j@XufgnYUZ5(uw}k>|NTEd%o!%JFerF2Ff1~=&hTLF*2b+r>I@HYK!kuYr=%Ey&zRmn z{V}~wkilUJ1A_}EkTPZPOU(Nf(Wjnnz(ht!Zjxu1erwnIzxR%Z2mY>#>_##fY5|mb z&G19ReQx=Cn_8|OpcA1kC7yc2e!%_aF8BX8`ww^FG$4lkz|ySecdze@yOzYlAfU>? z5XeLdm1@u6_i*30<3%=>%}72mWmq<2_P*(l&+{PSK_i=iXXRPb`oDkvet#^w|C{K2 z^f0gYIp5S&EI>K^{-jhoIo;n z-hrAa6MueRTm1k04fY#V4E|{d8=hJ*OfxUCpRa3toqf*7njMpn3?=mO6 z-~W1_!y4oSRmz}~`QG-I`c|}@-=njfUINCNluyfcg6EL4^Lj#zL0|OZYpoX@tf8A{+~Jj;ojfI{#nPj%N-Dw zK*UZYGed_FA|_D_msz)jD_+mjU8l=XVTbV3ij}4f+Hd#P|2p%_B{BE$y6SiGUuX3c z|C#^z)c@mc_s%P>XF5;>P3vvf7`~kozi;~7!f3zQ=IgIt{oZlzO}({o`OlTdKcAHO zUmE*!FH%B^dS=DYw{@%E=JLJl7T2a`o4FwpwR1Lua&eIIdG>@mH?LIpi1*e%!5?luH~HN2J?DHr z=X-9+r_mf|+I|`UI7dZ>odmG6zEZ$(8;-8V`B}j!Co)b5;PUJCL%HVb@(O@`d{o#+ zpNXoLrg>RY5niFAK?`}!%J<&T4HcbZd-?2n>2TnD8DFF>OiLIz@h;PoQ4_fNd`+iK zg7r-iMuk~q54?U9p!WX~?YO!Cae*xUUT}L8;DjBx8L%1NCP0UW@AYEoXJa)P~Q7phEag={jZfCBb`0W+=8F1uTS0ken2%i&!e9Gs`Y0Yt7OB4!#Zeuwn& zF0~8elq;?IeCg6N!HUMBh_z|*;_sMpC<4PVmM25y9-;Q1Tw}I$+crGWm&oFjvh@WT zZnFB!jU~3jf3;#=K#KUrj%?*%J~Z;hth!dE_VXQcw>{>=Tf$q;{w>{{Et+`iJKwF0 z(?k(-d@%k&VUx5!9zbp4sOb@E`O{NRD`nh70N<;guLst{h_CljNUY7aBN zCv)zv2R`WijCKtw=`?v}Fno@P@ zyjOwIVnasN304<#Q_4`ad2E=v9AN6oz%})@2Sjl+^&zGW?h}Uzmdu-EzI38EC7h$_ z#N|TqqWQpm!F8dbJtpQ$qUE_DxE|1=cjGY16rq z89qAv|Dg-@N@}r(~GK;}F|lEj6~VwKR_T{r4j+V+hiB=7pi;XwHa-#kc^T>@e&^j z_9G$qLrJaQlxV!dERY^o4oDp}x{>06uaN3fN*WBkxO43${i$Bl@1x_@`f6Np5G&$I zE$a{Q?6O53+hBI$wyg;Uh<4H{bPzZ`R>eQ7p;qZeDk=z}9?89XtC8DCjcYH;P4YcM zlx+B5jj0!F%F#YaEo&-p6*+)cUes&pa#8f->~(Xot~*GH2UB7zcXwgW$&o8eC*JwT Q)_)H~g-3_UKTbaPH)Y0Q@&Et; diff --git a/applications/external/doom/assets/screenshot3.png b/applications/external/doom/assets/screenshot3.png deleted file mode 100644 index b5aec03fdccb77f978d836ea80ecb1ee898154a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1629 zcmc&#drVVj6hDR04n$z0ggRHr%z_#6kY>CD#x`a}7la8+6bc!5%Vw1d_@cIedqf6V z!{!vSLZf>`2cw`t9gnskI>4?SnXz;XI!C37rMFN@OK%^$uFHD;Z~ytn&AB;W&iS45 zJHPXN^;wyW)qd;!0AO{-j`Vi{yzpNVJpaV(T+ENbjW1_MekDM_@RN`9RYbsx0OY`o z^fz)&2K#iSkW)pGW7UP^=bavvck}+Pru)+Ft(X;L+c_Mu0$hk3AP2y zF&_=p%uYT)!CL?qpM$WS&(zGB=O`fiiOF}`EYcdO)L}74(ELFa47Hm{a3dZ zd^e*eGQyqE9atchxFAp{wyGJo#9 z<4Gl~Qkv`t;%g)xwx?uS*$3lh_&$bVzyD-9mY??Rp{YHw6`D~hW<`9Hzx3qGd7o^Q zSAJ}$M#fw915x`iJzX@T<@;ayo7{xgui9N4V z*d^FH%`S!N8k5^OlVFJ`xZ^3}!%-?EkB$5>!gTe@LnVl(-yW@hG1{ijwNN@L1Ve={ zsl^&>Jw3c^AMYGNZsw9}DVJa1D!r1paU3lsw%V2Yk$1|p`}9+q_`qWF*EMwUi5Mu@ z?baR+Cu6YsrOqEP-#lr^dx^2wf^g4MsQGEe@p}VdEKP8inI~K|{OZ#U=~GsfAGOhyCe?+LaJAc`_OVu&O;@@ta?#e|So>S^skYHfqskCwDM-yKkR# z>b6d5wi0T(K$T59{%T*|z*ts|iEdSEP2~c8VQ+|1w^F2{i(5U4yc>&?(xpl~d@%Fs z@#&jFdsN5c7L|gaq%v~MmGIXVQPC(f+QzXN5!iVhN!9VRDUbHERE=F5ZR%;A oeZ;b47yXP5B_qyl1Pz$ulXAWbLp3j}@%I8U-p)+#e6#rU-{AE`xBvhE diff --git a/applications/external/geiger/flipper_geiger.c b/applications/external/geiger/flipper_geiger.c index a5503eb90..9c3d0d3fc 100644 --- a/applications/external/geiger/flipper_geiger.c +++ b/applications/external/geiger/flipper_geiger.c @@ -39,33 +39,53 @@ typedef struct { static void draw_callback(Canvas* canvas, void* ctx) { furi_assert(ctx); - mutexStruct displayStruct; - mutexStruct* geigerMutex = ctx; - furi_mutex_acquire(geigerMutex->mutex, FuriWaitForever); - memcpy(&displayStruct, geigerMutex, sizeof(mutexStruct)); - furi_mutex_release(geigerMutex->mutex); + mutexStruct* mutexVal = ctx; + mutexStruct mutexDraw; + furi_mutex_acquire(mutexVal->mutex, FuriWaitForever); + memcpy(&mutexDraw, mutexVal, sizeof(mutexStruct)); + furi_mutex_release(mutexVal->mutex); char buffer[32]; - if(displayStruct.data == 0) - snprintf( - buffer, sizeof(buffer), "%ld cps - %ld cpm", displayStruct.cps, displayStruct.cpm); - else if(displayStruct.data == 1) + if(mutexDraw.data == 0) + snprintf(buffer, sizeof(buffer), "%ld cps - %ld cpm", mutexDraw.cps, mutexDraw.cpm); + else if(mutexDraw.data == 1) snprintf( buffer, sizeof(buffer), "%ld cps - %.2f uSv/h", - displayStruct.cps, - ((double)displayStruct.cpm * (double)CONVERSION_FACTOR)); - else + mutexDraw.cps, + ((double)mutexDraw.cpm * (double)CONVERSION_FACTOR)); + else if(mutexDraw.data == 2) snprintf( buffer, sizeof(buffer), "%ld cps - %.2f mSv/y", - displayStruct.cps, - (((double)displayStruct.cpm * (double)CONVERSION_FACTOR)) * (double)8.76); + mutexDraw.cps, + (((double)mutexDraw.cpm * (double)CONVERSION_FACTOR)) * (double)8.76); + else if(mutexDraw.data == 3) + snprintf( + buffer, + sizeof(buffer), + "%ld cps - %.4f Rad/h", + mutexDraw.cps, + ((double)mutexDraw.cpm * (double)CONVERSION_FACTOR) / (double)10000); + else if(mutexDraw.data == 4) + snprintf( + buffer, + sizeof(buffer), + "%ld cps - %.2f mR/h", + mutexDraw.cps, + ((double)mutexDraw.cpm * (double)CONVERSION_FACTOR) / (double)10); + else + snprintf( + buffer, + sizeof(buffer), + "%ld cps - %.2f uR/h", + mutexDraw.cps, + ((double)mutexDraw.cpm * (double)CONVERSION_FACTOR) * (double)100); for(int i = 0; i < SCREEN_SIZE_X; i += 2) { - float Y = SCREEN_SIZE_Y - (displayStruct.line[i / 2] * displayStruct.coef); + float Y = SCREEN_SIZE_Y - (mutexDraw.line[i / 2] * mutexDraw.coef); canvas_draw_line(canvas, i, Y, i, SCREEN_SIZE_Y); canvas_draw_line(canvas, i + 1, Y, i + 1, SCREEN_SIZE_Y); @@ -103,8 +123,7 @@ static void gpiocallback(void* ctx) { furi_message_queue_put(queue, &event, 0); } -int32_t flipper_geiger_app(void* p) { - UNUSED(p); +int32_t flipper_geiger_app() { EventApp event; FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp)); @@ -127,7 +146,7 @@ int32_t flipper_geiger_app(void* p) { } ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, draw_callback, &mutexVal); + view_port_draw_callback_set(view_port, draw_callback, &mutexVal.mutex); view_port_input_callback_set(view_port, input_callback, event_queue); furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue); @@ -167,7 +186,7 @@ int32_t flipper_geiger_app(void* p) { if(mutexVal.data != 0) mutexVal.data--; else - mutexVal.data = 2; + mutexVal.data = 5; screenRefresh = 1; furi_mutex_release(mutexVal.mutex); @@ -175,7 +194,7 @@ int32_t flipper_geiger_app(void* p) { event.input.type == InputTypeShort)) { furi_mutex_acquire(mutexVal.mutex, FuriWaitForever); - if(mutexVal.data != 2) + if(mutexVal.data != 5) mutexVal.data++; else mutexVal.data = 0; diff --git a/applications/external/gpio_reader_a/GPIO_reader.c b/applications/external/gpioreader_a/GPIO_reader.c similarity index 100% rename from applications/external/gpio_reader_a/GPIO_reader.c rename to applications/external/gpioreader_a/GPIO_reader.c diff --git a/applications/external/gpio_reader_a/GPIO_reader_item.c b/applications/external/gpioreader_a/GPIO_reader_item.c similarity index 100% rename from applications/external/gpio_reader_a/GPIO_reader_item.c rename to applications/external/gpioreader_a/GPIO_reader_item.c diff --git a/applications/external/gpio_reader_a/GPIO_reader_item.h b/applications/external/gpioreader_a/GPIO_reader_item.h similarity index 100% rename from applications/external/gpio_reader_a/GPIO_reader_item.h rename to applications/external/gpioreader_a/GPIO_reader_item.h diff --git a/applications/external/gpio_reader_a/application.fam b/applications/external/gpioreader_a/application.fam similarity index 100% rename from applications/external/gpio_reader_a/application.fam rename to applications/external/gpioreader_a/application.fam diff --git a/applications/external/gpio_reader_a/icon.png b/applications/external/gpioreader_a/icon.png similarity index 100% rename from applications/external/gpio_reader_a/icon.png rename to applications/external/gpioreader_a/icon.png diff --git a/applications/external/gpio_reader_b/LICENSE b/applications/external/gpioreader_b/LICENSE similarity index 100% rename from applications/external/gpio_reader_b/LICENSE rename to applications/external/gpioreader_b/LICENSE diff --git a/applications/external/gpio_reader_b/application.fam b/applications/external/gpioreader_b/application.fam similarity index 100% rename from applications/external/gpio_reader_b/application.fam rename to applications/external/gpioreader_b/application.fam diff --git a/applications/external/gpio_reader_b/gpio_app.c b/applications/external/gpioreader_b/gpio_app.c similarity index 100% rename from applications/external/gpio_reader_b/gpio_app.c rename to applications/external/gpioreader_b/gpio_app.c diff --git a/applications/external/gpio_reader_b/gpio_app.h b/applications/external/gpioreader_b/gpio_app.h similarity index 100% rename from applications/external/gpio_reader_b/gpio_app.h rename to applications/external/gpioreader_b/gpio_app.h diff --git a/applications/external/gpio_reader_b/gpio_app_i.h b/applications/external/gpioreader_b/gpio_app_i.h similarity index 100% rename from applications/external/gpio_reader_b/gpio_app_i.h rename to applications/external/gpioreader_b/gpio_app_i.h diff --git a/applications/external/gpio_reader_b/gpio_custom_event.h b/applications/external/gpioreader_b/gpio_custom_event.h similarity index 100% rename from applications/external/gpio_reader_b/gpio_custom_event.h rename to applications/external/gpioreader_b/gpio_custom_event.h diff --git a/applications/external/gpio_reader_b/gpio_item.c b/applications/external/gpioreader_b/gpio_item.c similarity index 100% rename from applications/external/gpio_reader_b/gpio_item.c rename to applications/external/gpioreader_b/gpio_item.c diff --git a/applications/external/gpio_reader_b/gpio_item.h b/applications/external/gpioreader_b/gpio_item.h similarity index 100% rename from applications/external/gpio_reader_b/gpio_item.h rename to applications/external/gpioreader_b/gpio_item.h diff --git a/applications/external/gpio_reader_b/icon.png b/applications/external/gpioreader_b/icon.png similarity index 100% rename from applications/external/gpio_reader_b/icon.png rename to applications/external/gpioreader_b/icon.png diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene.c b/applications/external/gpioreader_b/scenes/gpio_scene.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene.c rename to applications/external/gpioreader_b/scenes/gpio_scene.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene.h b/applications/external/gpioreader_b/scenes/gpio_scene.h similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene.h rename to applications/external/gpioreader_b/scenes/gpio_scene.h diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_config.h b/applications/external/gpioreader_b/scenes/gpio_scene_config.h similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_config.h rename to applications/external/gpioreader_b/scenes/gpio_scene_config.h diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_reader.c b/applications/external/gpioreader_b/scenes/gpio_scene_reader.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_reader.c rename to applications/external/gpioreader_b/scenes/gpio_scene_reader.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_start.c b/applications/external/gpioreader_b/scenes/gpio_scene_start.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_start.c rename to applications/external/gpioreader_b/scenes/gpio_scene_start.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_test.c b/applications/external/gpioreader_b/scenes/gpio_scene_test.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_test.c rename to applications/external/gpioreader_b/scenes/gpio_scene_test.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart.c b/applications/external/gpioreader_b/scenes/gpio_scene_usb_uart.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart.c rename to applications/external/gpioreader_b/scenes/gpio_scene_usb_uart.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart_close_rpc.c b/applications/external/gpioreader_b/scenes/gpio_scene_usb_uart_close_rpc.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart_close_rpc.c rename to applications/external/gpioreader_b/scenes/gpio_scene_usb_uart_close_rpc.c diff --git a/applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart_config.c b/applications/external/gpioreader_b/scenes/gpio_scene_usb_uart_config.c similarity index 100% rename from applications/external/gpio_reader_b/scenes/gpio_scene_usb_uart_config.c rename to applications/external/gpioreader_b/scenes/gpio_scene_usb_uart_config.c diff --git a/applications/external/gpio_reader_b/usb_uart_bridge.c b/applications/external/gpioreader_b/usb_uart_bridge.c similarity index 100% rename from applications/external/gpio_reader_b/usb_uart_bridge.c rename to applications/external/gpioreader_b/usb_uart_bridge.c diff --git a/applications/external/gpio_reader_b/usb_uart_bridge.h b/applications/external/gpioreader_b/usb_uart_bridge.h similarity index 100% rename from applications/external/gpio_reader_b/usb_uart_bridge.h rename to applications/external/gpioreader_b/usb_uart_bridge.h diff --git a/applications/external/gpio_reader_b/views/gpio_reader.c b/applications/external/gpioreader_b/views/gpio_reader.c similarity index 100% rename from applications/external/gpio_reader_b/views/gpio_reader.c rename to applications/external/gpioreader_b/views/gpio_reader.c diff --git a/applications/external/gpio_reader_b/views/gpio_reader.h b/applications/external/gpioreader_b/views/gpio_reader.h similarity index 100% rename from applications/external/gpio_reader_b/views/gpio_reader.h rename to applications/external/gpioreader_b/views/gpio_reader.h diff --git a/applications/external/gpio_reader_b/views/gpio_test.c b/applications/external/gpioreader_b/views/gpio_test.c similarity index 100% rename from applications/external/gpio_reader_b/views/gpio_test.c rename to applications/external/gpioreader_b/views/gpio_test.c diff --git a/applications/external/gpio_reader_b/views/gpio_test.h b/applications/external/gpioreader_b/views/gpio_test.h similarity index 100% rename from applications/external/gpio_reader_b/views/gpio_test.h rename to applications/external/gpioreader_b/views/gpio_test.h diff --git a/applications/external/gpio_reader_b/views/gpio_usb_uart.c b/applications/external/gpioreader_b/views/gpio_usb_uart.c similarity index 98% rename from applications/external/gpio_reader_b/views/gpio_usb_uart.c rename to applications/external/gpioreader_b/views/gpio_usb_uart.c index f71dcccab..14f8c12fe 100644 --- a/applications/external/gpio_reader_b/views/gpio_usb_uart.c +++ b/applications/external/gpioreader_b/views/gpio_usb_uart.c @@ -82,7 +82,7 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) { if(model->rx_active) canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpFilled_14x15, IconRotation180); else - canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpFilled_14x15, IconRotation180); + canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpEmpty_14x15, IconRotation180); } static bool gpio_usb_uart_input_callback(InputEvent* event, void* context) { diff --git a/applications/external/gpio_reader_b/views/gpio_usb_uart.h b/applications/external/gpioreader_b/views/gpio_usb_uart.h similarity index 100% rename from applications/external/gpio_reader_b/views/gpio_usb_uart.h rename to applications/external/gpioreader_b/views/gpio_usb_uart.h diff --git a/applications/external/metronome/img/screenshot.png b/applications/external/metronome/img/screenshot.png deleted file mode 100644 index 7b6916e81ac8e1984370d33397ac6664f57b5f6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1978 zcmbVNeNfV89Dfj<<<4w%mCJ-~)oST!>0D|8uCo_4JJST;>CPr6x~!O@5@4OHZKbU% z(tOEW(<~G%MDYdjT9bJSxP_UR=*`UWB1{o}28xqO+ppU{tv`PE{GR9g{(QdQ&+~2M zk%P`o8=U|E&Y_1wq5!a4`bB^h)+KBvZr9SX^3mGKT`MRo!`@6Z~^7qY?jg_o`{I%fhMoE?uum{0A5MZ^6Vg#Mh@q@`#mYhv`r}1;{EQ`BguAMzJ z={1VP15jmCBr8!}zt#nA?n;V7fPyv4g4!?hfFEb}y|9)5G7mGzG8T}HL`p=U`j2Ud zZ%#~rX{KWG6@z2Mdpra7q|%aZa_;b02$HJi+BX#!mr5IB78_D4>u2W_jdozgHURdm z1o@FMn0#&^p*Viv$M{^aVeIlAwVY`R?Sy`SsCDa>^A7`{V5b&w{i$4gEIejQadZozvGR4?%v8jj$ zi!2>N-YzVNr|6)778N2fK%1m2och@bY`zYb)AOTk-!)!6P@HhOf`PkrmAAoTDPOx~ z`2;p!TpK5pb!>00ar}OsA>U|1q(6jtC*}ciF@TH{BkR_R5M3cQyVqsE%hnJ;1Gv*? z?@q8FS4hFQG47v!-BMIvlt7+n^_NfRZ)RC8zi9uR21m3E6`Uq`2pPGvu9MoV!<=v| za~7$9!#g>RW)IX$R4mfCMzG*XP&H#Xh)P3%#>bn4cVo(5QM#d?-qYo8cr}9@LUclq zMdJkp_dg}`(z>~@+ItNkk=>g#Wtm?Xq3tKp8@QyoSp~xZ?xGb1ba}G%1ohXNWFji< zM8r_X^D-FVzagLXu^7Q(>_PeT%^AY1tA2w=o`VUyL6(F5MWOV#o@HK|h=&iF`LC*I8kmjY|aTOy_>U2s1= z2Yuz>qCEY|D3vG8evyMOYZ&N$Ql=}U61B`y|5f1Qf5uIV+(Bp1byFneZV5}x!d#xG z6Rg_4QA&SWrqB*n15Zo`Kt@4ZIc77<*0$EEdbjpccZr}VyRBsgY&I;2Uz6i)txHPZ z{ZI71B3<`Y3JF$T8w6wvh)!yq`HIFd_Fpcr^3Ln2w6V)uZ)>$Wdn|2m8}QyTikzR| z|5Rk(74@3Sa_2?;@@ovxH9lPejlhS$ZPf8p>Iw1t`BWH;Zyof1C#+hU#(5!=$q=I+ zZLrZUelJtv-|+Iy_H-+Wk;YUCE)JLw5_T5sj%t_qGNs}{Q#ZBxKyI_NbX;3Y#k35N zVtwy&i+D4wGIB;cbdB6Cd{o|Sx|LyQhuca^(VTlC)>AH?Bc1U%bEE>dRhq)q55f3r z9R#vFismx<{Gjzs@>D8Gn4;vp65!Y#l&_47)i_%AbNul3a>5o~n~O5TtkB1D(JKVj6sxDd;hFZ`10iAvCa02&=^aJR{jJL+3* z%y@1f`!jvSr6Ly1SBnH=Yi#nJjP;RhMi-gq%c!YAwaLv#t7J|KK!*gkOKj~MBUsC? zLHC>Ef(b^V>1+w!EMzMvf$CU4(H9YZdj6wP8du-ilMJ2}*(@+5mwX?AT9QV;^y%Kt oCuNK}+uQP=Dfs)r1Y-v*$QL~Uk1Kkr_|}uq{YOGL`;MRg3sjKxR{#J2 diff --git a/applications/external/minesweeper/img/screenshot.png b/applications/external/minesweeper/img/screenshot.png deleted file mode 100644 index 65b307c550cdfc13c388135b4e286d1be56957d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1842 zcmbtVc~BEq7=IyRgcgu0lNROZV5T#7|k6~v9}^R?EPJl zBCckac0tDKDHDB)&E87M8+q{t=h*b7A$KRhV%w@b}PgcgWS4FPo7UFZGEXhdN81u1de_LK+PP$ zsQ-lrLXhnzD}BG1!on)ucSr&5&)qBH2AsQ8O9t~kdlSfcO9bQd0KiyA0`oTkaCD$* zYv;&Vc~b;u-O9C;8JSC^LE_FVG}yv)al|S=f}-Piv@|@)jMR1z+6vs<-w#_hljONO z0y(-b+wpdTA<@2EE3JbPcZMdMt1(zwv-tGq7Slq=_!UaQ;gPGcAapi5eE&Xruf!V! zpK)f><@h6VOJ|yyOzwdL9)IaB*Nj!2ZH*It5;K!Y7hY#C0)y;nUF72lEu|g~9eoWH zVk*m6&SN@cT)ZnLOyjszN@qLv+_4|VOE8tgDia9!kbn7(XrV9b-ZVR3(}T*;MfLXO zM{uqFcnD-V^x8 z-7(UvLMBPwi*?*-KLlypY%534XE{Fi*P(OwbB?`QAzkNpVq&I@1M2Lr}c&4dcO`0E>xN~O!>eF(XAfJP?lz7M+ z{8TLMyVVV$L-+Yq|4AbyOTu^99Qx=h1GwsOVWT|;D|x3ebem5#-gc%84>74@kwJE* zBMPy+g8Q=UA^D+}-GJN)Kw9+<`NU{lIMfx+uP+q%o}cseKD+O~n}cOMa6+bTt`=jr zaLA+XKn6K^Fq!8!dVJMOh)wbic<}$%y3dM$w7%+c270qNN5ILOmVXTuKM5rV zZ4LU!2&y7VaFM__WMhuxyNFVavqwiE-MxVfj3-(!!srt~tfN5MLIkp5Tb;A^0M@y&|tLV8cCM1-cd+b59W z;+(jX&}2Fjk;9}>73wszruDURZgYMk@L4mlH?JaSv{b+_V;rQ^E#u;U`kns)=Ov_G z85b1lcsCl*l=K`vreg`zY7U9?mh0Yf*Bk14kL`@TnP=zI>$Y&a6)#NaYnFC62x6qc znb;9!nsMo2(!ak7Cs(@|<}H=J-*(36lkctWE&l1cC7M!Smn30bQoLeK?vZ~0WMt2h diff --git a/applications/external/musictracker/application.fam b/applications/external/music_tracker/application.fam similarity index 90% rename from applications/external/musictracker/application.fam rename to applications/external/music_tracker/application.fam index fe4355e86..f3bac02c2 100644 --- a/applications/external/musictracker/application.fam +++ b/applications/external/music_tracker/application.fam @@ -10,4 +10,5 @@ App( order=20, fap_icon="zero_tracker.png", fap_category="Music", + fap_icon_assets="icons", ) diff --git a/applications/external/musictracker/tracker_engine/speaker_hal.c b/applications/external/music_tracker/tracker_engine/speaker_hal.c similarity index 91% rename from applications/external/musictracker/tracker_engine/speaker_hal.c rename to applications/external/music_tracker/tracker_engine/speaker_hal.c index 94489f1b6..208fee04c 100644 --- a/applications/external/musictracker/tracker_engine/speaker_hal.c +++ b/applications/external/music_tracker/tracker_engine/speaker_hal.c @@ -40,17 +40,12 @@ void tracker_speaker_stop() { } void tracker_speaker_init() { - if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) { - furi_hal_speaker_start(200.0f, 0.01f); - tracker_speaker_stop(); - } + furi_hal_speaker_start(200.0f, 0.01f); + tracker_speaker_stop(); } void tracker_speaker_deinit() { - if(furi_hal_speaker_is_mine()) { - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } + furi_hal_speaker_stop(); } static FuriHalInterruptISR tracker_isr; diff --git a/applications/external/musictracker/tracker_engine/speaker_hal.h b/applications/external/music_tracker/tracker_engine/speaker_hal.h similarity index 100% rename from applications/external/musictracker/tracker_engine/speaker_hal.h rename to applications/external/music_tracker/tracker_engine/speaker_hal.h diff --git a/applications/external/musictracker/tracker_engine/tracker.c b/applications/external/music_tracker/tracker_engine/tracker.c similarity index 100% rename from applications/external/musictracker/tracker_engine/tracker.c rename to applications/external/music_tracker/tracker_engine/tracker.c diff --git a/applications/external/musictracker/tracker_engine/tracker.h b/applications/external/music_tracker/tracker_engine/tracker.h similarity index 100% rename from applications/external/musictracker/tracker_engine/tracker.h rename to applications/external/music_tracker/tracker_engine/tracker.h diff --git a/applications/external/musictracker/tracker_engine/tracker_notes.h b/applications/external/music_tracker/tracker_engine/tracker_notes.h similarity index 100% rename from applications/external/musictracker/tracker_engine/tracker_notes.h rename to applications/external/music_tracker/tracker_engine/tracker_notes.h diff --git a/applications/external/musictracker/tracker_engine/tracker_song.h b/applications/external/music_tracker/tracker_engine/tracker_song.h similarity index 100% rename from applications/external/musictracker/tracker_engine/tracker_song.h rename to applications/external/music_tracker/tracker_engine/tracker_song.h diff --git a/applications/external/musictracker/view/tracker_view.c b/applications/external/music_tracker/view/tracker_view.c similarity index 100% rename from applications/external/musictracker/view/tracker_view.c rename to applications/external/music_tracker/view/tracker_view.c diff --git a/applications/external/musictracker/view/tracker_view.h b/applications/external/music_tracker/view/tracker_view.h similarity index 100% rename from applications/external/musictracker/view/tracker_view.h rename to applications/external/music_tracker/view/tracker_view.h diff --git a/applications/external/musictracker/zero_tracker.c b/applications/external/music_tracker/zero_tracker.c similarity index 100% rename from applications/external/musictracker/zero_tracker.c rename to applications/external/music_tracker/zero_tracker.c diff --git a/applications/external/musictracker/zero_tracker.h b/applications/external/music_tracker/zero_tracker.h similarity index 100% rename from applications/external/musictracker/zero_tracker.h rename to applications/external/music_tracker/zero_tracker.h diff --git a/applications/external/musictracker/zero_tracker.png b/applications/external/music_tracker/zero_tracker.png similarity index 100% rename from applications/external/musictracker/zero_tracker.png rename to applications/external/music_tracker/zero_tracker.png diff --git a/applications/external/nightstand_clock/application.fam b/applications/external/nightstand/application.fam similarity index 100% rename from applications/external/nightstand_clock/application.fam rename to applications/external/nightstand/application.fam diff --git a/applications/external/nightstand_clock/clock.png b/applications/external/nightstand/clock.png similarity index 100% rename from applications/external/nightstand_clock/clock.png rename to applications/external/nightstand/clock.png diff --git a/applications/external/nightstand_clock/clock_app.c b/applications/external/nightstand/clock_app.c similarity index 100% rename from applications/external/nightstand_clock/clock_app.c rename to applications/external/nightstand/clock_app.c diff --git a/applications/external/nightstand_clock/clock_app.h b/applications/external/nightstand/clock_app.h similarity index 100% rename from applications/external/nightstand_clock/clock_app.h rename to applications/external/nightstand/clock_app.h diff --git a/applications/external/pomodoro/flipp_pomodoro_app.c b/applications/external/pomodoro/flipp_pomodoro_app.c index 5adca1edb..2ddf8cf68 100644 --- a/applications/external/pomodoro/flipp_pomodoro_app.c +++ b/applications/external/pomodoro/flipp_pomodoro_app.c @@ -78,6 +78,7 @@ void flipp_pomodoro_app_free(FlippPomodoroApp* app) { view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); flipp_pomodoro_view_timer_free(app->timer_view); + flipp_pomodoro__destroy(app->state); free(app); furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/external/pomodoro/modules/flipp_pomodoro.c b/applications/external/pomodoro/modules/flipp_pomodoro.c index 161e862f8..9915025fb 100644 --- a/applications/external/pomodoro/modules/flipp_pomodoro.c +++ b/applications/external/pomodoro/modules/flipp_pomodoro.c @@ -55,6 +55,11 @@ char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) { return next_stage_label[flipp_pomodoro__stage_by_index(state->current_stage_index + 1)]; }; +void flipp_pomodoro__destroy(FlippPomodoroState* state) { + furi_assert(state); + free(state); +}; + uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) { const int32_t stage_duration_seconds_map[] = { [FlippPomodoroStageFocus] = 25 * TIME_SECONDS_IN_MINUTE, diff --git a/applications/external/pong/flipper_pong.c b/applications/external/pong/flipper_pong.c index 55b371ad5..53c6a7e27 100644 --- a/applications/external/pong/flipper_pong.c +++ b/applications/external/pong/flipper_pong.c @@ -15,8 +15,7 @@ #define PAD_SIZE_X 3 #define PAD_SIZE_Y 8 -#define PLAYER1_PAD_SPEED 4 - +#define PLAYER1_PAD_SPEED 2 #define PLAYER2_PAD_SPEED 2 #define BALL_SIZE 4 @@ -39,29 +38,22 @@ typedef struct Players { static void draw_callback(Canvas* canvas, void* ctx) { furi_assert(ctx); - Players* playersMutex = ctx; - furi_mutex_acquire(playersMutex->mutex, FuriWaitForever); + Players* players = ctx; + furi_mutex_acquire(players->mutex, FuriWaitForever); canvas_draw_frame(canvas, 0, 0, 128, 64); - canvas_draw_box( - canvas, playersMutex->player1_X, playersMutex->player1_Y, PAD_SIZE_X, PAD_SIZE_Y); - canvas_draw_box( - canvas, playersMutex->player2_X, playersMutex->player2_Y, PAD_SIZE_X, PAD_SIZE_Y); - canvas_draw_box(canvas, playersMutex->ball_X, playersMutex->ball_Y, BALL_SIZE, BALL_SIZE); + canvas_draw_box(canvas, players->player1_X, players->player1_Y, PAD_SIZE_X, PAD_SIZE_Y); + canvas_draw_box(canvas, players->player2_X, players->player2_Y, PAD_SIZE_X, PAD_SIZE_Y); + canvas_draw_box(canvas, players->ball_X, players->ball_Y, BALL_SIZE, BALL_SIZE); canvas_set_font(canvas, FontPrimary); canvas_set_font_direction(canvas, CanvasDirectionBottomToTop); char buffer[16]; - snprintf( - buffer, - sizeof(buffer), - "%u - %u", - playersMutex->player1_score, - playersMutex->player2_score); + snprintf(buffer, sizeof(buffer), "%u - %u", players->player1_score, players->player2_score); canvas_draw_str_aligned( canvas, SCREEN_SIZE_X / 2 + 15, SCREEN_SIZE_Y / 2 + 2, AlignCenter, AlignTop, buffer); - furi_mutex_release(playersMutex->mutex); + furi_mutex_release(players->mutex); } static void input_callback(InputEvent* input_event, void* ctx) { @@ -101,8 +93,7 @@ uint8_t changeDirection() { return randomuint8[0]; } -int32_t flipper_pong_app(void* p) { - UNUSED(p); +int32_t flipper_pong_app() { EventApp event; FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp)); @@ -129,7 +120,7 @@ int32_t flipper_pong_app(void* p) { } ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, draw_callback, &players); + view_port_draw_callback_set(view_port, draw_callback, &players.mutex); view_port_input_callback_set(view_port, input_callback, event_queue); Gui* gui = furi_record_open(RECORD_GUI); @@ -152,7 +143,6 @@ int32_t flipper_pong_app(void* p) { if(event.type == EventTypeInput) { if(event.input.key == InputKeyBack) { furi_mutex_release(players.mutex); - notification_message(notification, &sequence_set_only_green_255); break; } else if(event.input.key == InputKeyUp) { if(players.player1_Y >= 1 + PLAYER1_PAD_SPEED) diff --git a/applications/external/rc2014_coleco/coleco.c b/applications/external/rc2014_coleco/coleco.c index 311b0ceac..f0a4c6188 100644 --- a/applications/external/rc2014_coleco/coleco.c +++ b/applications/external/rc2014_coleco/coleco.c @@ -40,15 +40,14 @@ typedef struct { } PluginEvent; typedef struct { - FuriMutex* mutex; bool dpad; int row; int column; + FuriMutex* mutex; } Coleco; static void render_callback(Canvas* const canvas, void* context) { - furi_assert(context); - Coleco* coleco = context; + Coleco* coleco = (Coleco*)context; furi_mutex_acquire(coleco->mutex, FuriWaitForever); if(coleco->dpad) { @@ -175,12 +174,20 @@ static Coleco* coleco_alloc() { coleco->row = 0; coleco->column = 1; + coleco->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(!coleco->mutex) { + FURI_LOG_E("Coleco", "cannot create mutex\r\n"); + free(coleco); + return NULL; + } + return coleco; } static void coleco_free(Coleco* coleco) { furi_assert(coleco); + furi_mutex_free(coleco->mutex); free(coleco); } @@ -190,11 +197,7 @@ int32_t coleco_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); Coleco* coleco = coleco_alloc(); - - coleco->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!coleco->mutex) { - FURI_LOG_E("Coleco", "cannot create mutex\r\n"); - coleco_free(coleco); + if(coleco == NULL) { return 255; } @@ -346,6 +349,8 @@ int32_t coleco_app(void* p) { view_port_update(view_port); } + } else { + FURI_LOG_D("Coleco", "FuriMessageQueue: event timeout"); } furi_mutex_release(coleco->mutex); @@ -358,7 +363,6 @@ int32_t coleco_app(void* p) { furi_record_close("gui"); view_port_free(view_port); furi_message_queue_free(event_queue); - furi_mutex_free(coleco->mutex); coleco_free(coleco); return 0; } diff --git a/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c b/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c index 4c845b883..17e48473a 100644 --- a/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c +++ b/applications/external/rubiks_cube_scrambler/rubiks_cube_scrambler.c @@ -8,11 +8,11 @@ #include "scrambler.h" #include "furi_hal_random.h" -int scrambleStarted = 0; +bool scrambleStarted = false; char scramble_str[100] = {0}; char scramble_start[100] = {0}; char scramble_end[100] = {0}; -int notifications_enabled = 0; +bool notifications_enabled = false; static void success_vibration() { furi_hal_vibro_on(false); @@ -22,12 +22,12 @@ static void success_vibration() { return; } void split_array(char original[], int size, char first[], char second[]) { - int mid = size / 2; + int32_t mid = size / 2; if(size % 2 != 0) { mid++; } - int first_index = 0, second_index = 0; - for(int i = 0; i < size; i++) { + int32_t first_index = 0, second_index = 0; + for(int32_t i = 0; i < size; i++) { if(i < mid) { first[first_index++] = original[i]; } else { @@ -40,23 +40,17 @@ void split_array(char original[], int size, char first[], char second[]) { first[first_index] = '\0'; second[second_index] = '\0'; } +void genScramble() { + scrambleReplace(); + strcpy(scramble_str, printData()); + split_array(scramble_str, strlen(scramble_str), scramble_start, scramble_end); +} static void draw_callback(Canvas* canvas, void* ctx) { UNUSED(ctx); canvas_clear(canvas); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 4, 13, "Rubik's Cube Scrambler"); - - if(scrambleStarted) { - genScramble(); - scrambleReplace(); - strcpy(scramble_str, printData()); - if(notifications_enabled) { - success_vibration(); - } - split_array(scramble_str, strlen(scramble_str), scramble_start, scramble_end); - scrambleStarted = 0; - } canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned(canvas, 64, 28, AlignCenter, AlignCenter, scramble_start); canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignCenter, scramble_end); @@ -90,13 +84,16 @@ int32_t rubiks_cube_scrambler_main(void* p) { furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk); if(event.key == InputKeyOk && event.type == InputTypeShort) { - scrambleStarted = 1; + genScramble(); + if(notifications_enabled) { + success_vibration(); + } } if(event.key == InputKeyLeft && event.type == InputTypeShort) { if(notifications_enabled) { - notifications_enabled = 0; + notifications_enabled = false; } else { - notifications_enabled = 1; + notifications_enabled = true; success_vibration(); } } diff --git a/applications/external/rubiks_cube_scrambler/scrambler.c b/applications/external/rubiks_cube_scrambler/scrambler.c index ea5291940..b97a67400 100644 --- a/applications/external/rubiks_cube_scrambler/scrambler.c +++ b/applications/external/rubiks_cube_scrambler/scrambler.c @@ -12,66 +12,37 @@ Authors: Tanish Bhongade and RaZe // 6 moves along with direction char moves[6] = {'R', 'U', 'F', 'B', 'L', 'D'}; -char dir[4] = {' ', '\'', '2'}; -const int SLEN = 20; +char dir[4] = {'\'', '2'}; +const int32_t SLEN = 20; #define RESULT_SIZE 100 -// Structure which holds main scramble + struct GetScramble { char mainScramble[25][3]; }; -struct GetScramble a; // Its object - -// Function prototypes to avoid bugs -void scrambleReplace(); -void genScramble(); -void valid(); -int getRand(int upr, int lwr); -char* printData(); -void writeToFile(); - -// Main function -/* int main(){ - genScramble ();//Calling genScramble - scrambleReplace();//Calling scrambleReplace - valid();//Calling valid to validate the scramble - printData ();//Printing the final scramble - //writeToFile();//If you want to write to a file, please uncomment this - - return 0; -} */ - -void genScramble() { - // Stage 1 - for(int i = 0; i < SLEN; i++) { - strcpy(a.mainScramble[i], "00"); - } - // This makes array like this 00 00 00....... -} +struct GetScramble a; void scrambleReplace() { - // Stage 2 - // Actual process begins here - // Initialize the mainScramble array with all the possible moves - for(int i = 0; i < SLEN; i++) { + for(int32_t i = 0; i < SLEN; i++) { a.mainScramble[i][0] = moves[furi_hal_random_get() % 6]; a.mainScramble[i][1] = dir[furi_hal_random_get() % 3]; } - // Perform the Fisher-Yates shuffle - for(int i = 6 - 1; i > 0; i--) { - int j = rand() % (i + 1); + /* // Perform the Fisher-Yates shuffle + for (int32_t i = 6 - 1; i > 0; i--) + { + int32_t j = rand() % (i + 1); char temp[3]; strcpy(temp, a.mainScramble[i]); strcpy(a.mainScramble[i], a.mainScramble[j]); strcpy(a.mainScramble[j], temp); - } + } */ - // Select the first 10 elements as the scramble, using only the first three elements of the dir array - for(int i = 0; i < SLEN; i++) { + // Select the first 10 elements as the scramble, using only the first two elements of the dir array + for(int32_t i = 0; i < SLEN; i++) { a.mainScramble[i][1] = dir[furi_hal_random_get() % 3]; } - for(int i = 1; i < SLEN; i++) { + for(int32_t i = 1; i < SLEN; i++) { while(a.mainScramble[i][0] == a.mainScramble[i - 2][0] || a.mainScramble[i][0] == a.mainScramble[i - 1][0]) { a.mainScramble[i][0] = moves[furi_hal_random_get() % 5]; @@ -79,24 +50,11 @@ void scrambleReplace() { } } -// Let this function be here for now till I find out what is causing the extra space bug in the scrambles -void remove_double_spaces(char* str) { - int i, j; - int len = strlen(str); - for(i = 0, j = 0; i < len; i++, j++) { - if(str[i] == ' ' && str[i + 1] == ' ') { - i++; - } - str[j] = str[i]; - } - str[j] = '\0'; -} char* printData() { static char result[RESULT_SIZE]; - int offset = 0; - for(int loop = 0; loop < SLEN; loop++) { + int32_t offset = 0; + for(int32_t loop = 0; loop < SLEN; loop++) { offset += snprintf(result + offset, RESULT_SIZE - offset, "%s ", a.mainScramble[loop]); } - remove_double_spaces(result); return result; -} +} \ No newline at end of file diff --git a/applications/external/rubiks_cube_scrambler/scrambler.h b/applications/external/rubiks_cube_scrambler/scrambler.h index 4b56c565d..557ef20ae 100644 --- a/applications/external/rubiks_cube_scrambler/scrambler.h +++ b/applications/external/rubiks_cube_scrambler/scrambler.h @@ -1,3 +1,2 @@ void scrambleReplace(); -void genScramble(); char* printData(); diff --git a/applications/external/timelapse/icons/ButtonDownHollow_7x4.png b/applications/external/timelapse/icons/ButtonDownHollow_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..2b87c43647d56c78a2c5ff5ecee6b3c9641c57fa GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!2~4FF4?37q!^2X+?^QKos)S9l1X>;b!1@J z*w6hZkrl}2EbxddW?{W77j*6W#z~B_y7O*=kMVYCpZ{Ri)wIhc380j PXc~j3tDnm{r-UW|ZJjr; literal 0 HcmV?d00001 diff --git a/applications/external/timelapse/icons/ButtonLeftHollow_4x7.png b/applications/external/timelapse/icons/ButtonLeftHollow_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..374dc7d1ac7aa9c4725681c145ef2f61b7869b77 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c8!2~21uvfPODaPU;cPEB*=VV@jWYZme9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucK`l=g#}J9|v pae)j+>jQ^K9-aVZhZ;6Eh9@nu@2ZLtD}cHfJYD@<);T3K0RWG@CDZ@_ literal 0 HcmV?d00001 diff --git a/applications/external/timelapse/icons/ButtonRightHollow_4x7.png b/applications/external/timelapse/icons/ButtonRightHollow_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..acbb0859267d431885e1998146e04f2cdfdb46b9 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c8!2~21uvfPODaPU;cPEB*=VV@jWYZme9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucK@CqA#}J9|gTe~DWM4fbu1?j literal 0 HcmV?d00001 diff --git a/applications/external/timelapse/icons/ButtonUpHollow_7x4.png b/applications/external/timelapse/icons/ButtonUpHollow_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..e88ee332230e98938ba769e8813a671040140987 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!2~4FF4?37q!^2X+?^QKos)S9l1X>;b!1@J z*w6hZkrl}2EbxddW?mutex, FuriWaitForever); + + // Try to acquire the mutex for the plugin state variables, timeout = 25mS + if(furi_mutex_acquire(state->mutex, 25) != FuriStatusOk) return; switch(state->scene) { //--------------------------------------------------------------------- @@ -344,8 +347,7 @@ int32_t wii_ec_anal(void) { goto bail; } // 5. Create a mutex for (reading/writing) the plugin state variables - state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!state->mutex) { + if(!(state->mutex = furi_mutex_alloc(FuriMutexTypeNormal))) { ERROR(wii_errs[(error = ERR_NO_MUTEX)]); goto bail; } @@ -434,7 +436,10 @@ int32_t wii_ec_anal(void) { // Read successful // *** Try to lock the plugin state variables *** - furi_mutex_acquire(state->mutex, FuriWaitForever); + if(furi_mutex_acquire(state->mutex, FuriWaitForever) != FuriStatusOk) { + ERROR(wii_errs[(error = ERR_MUTEX_BLOCK)]); + goto bail; + } // *** Handle events *** switch(msg.id) { @@ -472,7 +477,10 @@ int32_t wii_ec_anal(void) { if(redraw) view_port_update(vpp); // *** Try to release the plugin state variables *** - furi_mutex_release(state->mutex); + if(furi_mutex_release(state->mutex) != FuriStatusOk) { + ERROR(wii_errs[(error = ERR_MUTEX_RELEASE)]); + goto bail; + } } while(state->run); // ===== Game Over ===== @@ -507,7 +515,10 @@ bail: } // 5. Free the mutex - furi_mutex_free(state->mutex); + if(state->mutex) { + furi_mutex_free(state->mutex); + state->mutex = NULL; + } // 4. Free up state pointer(s) // none diff --git a/applications/external/wii_ec_anal/wii_anal.h b/applications/external/wiiec/wii_anal.h similarity index 98% rename from applications/external/wii_ec_anal/wii_anal.h rename to applications/external/wiiec/wii_anal.h index d8997b030..3be398a54 100644 --- a/applications/external/wii_ec_anal/wii_anal.h +++ b/applications/external/wiiec/wii_anal.h @@ -56,7 +56,8 @@ typedef struct eventMsg { // Access to this memory is controlled by mutex // typedef struct state { - FuriMutex* mutex; + FuriMutex* mutex; // mutex for using this struct + bool run; // true : plugin is running bool timerEn; // controller scanning enabled diff --git a/applications/external/wii_ec_anal/wii_anal_ec.c b/applications/external/wiiec/wii_anal_ec.c similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_ec.c rename to applications/external/wiiec/wii_anal_ec.c diff --git a/applications/external/wii_ec_anal/wii_anal_ec.h b/applications/external/wiiec/wii_anal_ec.h similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_ec.h rename to applications/external/wiiec/wii_anal_ec.h diff --git a/applications/external/wii_ec_anal/wii_anal_keys.c b/applications/external/wiiec/wii_anal_keys.c similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_keys.c rename to applications/external/wiiec/wii_anal_keys.c diff --git a/applications/external/wii_ec_anal/wii_anal_keys.h b/applications/external/wiiec/wii_anal_keys.h similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_keys.h rename to applications/external/wiiec/wii_anal_keys.h diff --git a/applications/external/wii_ec_anal/wii_anal_lcd.c b/applications/external/wiiec/wii_anal_lcd.c similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_lcd.c rename to applications/external/wiiec/wii_anal_lcd.c diff --git a/applications/external/wii_ec_anal/wii_anal_lcd.h b/applications/external/wiiec/wii_anal_lcd.h similarity index 100% rename from applications/external/wii_ec_anal/wii_anal_lcd.h rename to applications/external/wiiec/wii_anal_lcd.h diff --git a/applications/external/wii_ec_anal/wii_anal_ver.h b/applications/external/wiiec/wii_anal_ver.h similarity index 85% rename from applications/external/wii_ec_anal/wii_anal_ver.h rename to applications/external/wiiec/wii_anal_ver.h index 3f2c8c0e6..df2659d57 100644 --- a/applications/external/wii_ec_anal/wii_anal_ver.h +++ b/applications/external/wiiec/wii_anal_ver.h @@ -5,5 +5,6 @@ #define VER_MAJ &img_3x5_1 #define VER_MIN &img_3x5_0 +#define VER_SUB &img_3x5_1 #endif //WII_ANAL_VER_H_ diff --git a/applications/external/wii_ec_anal/wii_ec.c b/applications/external/wiiec/wii_ec.c similarity index 100% rename from applications/external/wii_ec_anal/wii_ec.c rename to applications/external/wiiec/wii_ec.c diff --git a/applications/external/wii_ec_anal/wii_ec.h b/applications/external/wiiec/wii_ec.h similarity index 100% rename from applications/external/wii_ec_anal/wii_ec.h rename to applications/external/wiiec/wii_ec.h diff --git a/applications/external/wii_ec_anal/wii_ec_classic.c b/applications/external/wiiec/wii_ec_classic.c similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_classic.c rename to applications/external/wiiec/wii_ec_classic.c diff --git a/applications/external/wii_ec_anal/wii_ec_classic.h b/applications/external/wiiec/wii_ec_classic.h similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_classic.h rename to applications/external/wiiec/wii_ec_classic.h diff --git a/applications/external/wii_ec_anal/wii_ec_macros.h b/applications/external/wiiec/wii_ec_macros.h similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_macros.h rename to applications/external/wiiec/wii_ec_macros.h diff --git a/applications/external/wii_ec_anal/wii_ec_nunchuck.c b/applications/external/wiiec/wii_ec_nunchuck.c similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_nunchuck.c rename to applications/external/wiiec/wii_ec_nunchuck.c diff --git a/applications/external/wii_ec_anal/wii_ec_nunchuck.h b/applications/external/wiiec/wii_ec_nunchuck.h similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_nunchuck.h rename to applications/external/wiiec/wii_ec_nunchuck.h diff --git a/applications/external/wii_ec_anal/wii_ec_udraw.c b/applications/external/wiiec/wii_ec_udraw.c similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_udraw.c rename to applications/external/wiiec/wii_ec_udraw.c diff --git a/applications/external/wii_ec_anal/wii_ec_udraw.h b/applications/external/wiiec/wii_ec_udraw.h similarity index 100% rename from applications/external/wii_ec_anal/wii_ec_udraw.h rename to applications/external/wiiec/wii_ec_udraw.h diff --git a/applications/external/wii_ec_anal/wii_i2c.c b/applications/external/wiiec/wii_i2c.c similarity index 100% rename from applications/external/wii_ec_anal/wii_i2c.c rename to applications/external/wiiec/wii_i2c.c diff --git a/applications/external/wii_ec_anal/wii_i2c.h b/applications/external/wiiec/wii_i2c.h similarity index 100% rename from applications/external/wii_ec_anal/wii_i2c.h rename to applications/external/wiiec/wii_i2c.h From ffa7b74e18d114c0143d03a67b3ad3df71ce8f6a Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 18:03:55 +0100 Subject: [PATCH 087/216] Fix build --- applications/external/music_tracker/application.fam | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/external/music_tracker/application.fam b/applications/external/music_tracker/application.fam index f3bac02c2..fe4355e86 100644 --- a/applications/external/music_tracker/application.fam +++ b/applications/external/music_tracker/application.fam @@ -10,5 +10,4 @@ App( order=20, fap_icon="zero_tracker.png", fap_category="Music", - fap_icon_assets="icons", ) From 356db794b5f219d8fa1b1f58a6ae261676c42d49 Mon Sep 17 00:00:00 2001 From: clipboard1 Date: Tue, 2 May 2023 22:25:05 +0500 Subject: [PATCH 088/216] Added numpad keyboard --- applications/external/hid_app/hid.c | 15 + applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../external/hid_app/views/hid_numpad.c | 302 ++++++++++++++++++ .../external/hid_app/views/hid_numpad.h | 14 + 5 files changed, 334 insertions(+) create mode 100644 applications/external/hid_app/views/hid_numpad.c create mode 100644 applications/external/hid_app/views/hid_numpad.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index f29a3b22a..791f6b2e4 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -9,6 +9,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, + HidSubmenuIndexNumpad, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, HidSubmenuIndexYTShorts, @@ -28,6 +29,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); + } else if(index == HidSubmenuIndexNumpad) { + app->view_id = HidViewNumpad; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewNumpad); } else if(index == HidSubmenuIndexMedia) { app->view_id = HidViewMedia; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMedia); @@ -60,6 +64,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keynote_set_connected_status(hid->hid_keynote, connected); hid_keynote_vertical_set_connected_status(hid->hid_keynote_vertical, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected); + hid_numpad_set_connected_status(hid->hid_numpad, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); @@ -118,6 +123,8 @@ Hid* hid_alloc(HidTransport transport) { app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Numpad keyboard", HidSubmenuIndexNumpad, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); submenu_add_item( @@ -185,6 +192,12 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewKeyboard, hid_keyboard_get_view(app->hid_keyboard)); + //Numpad keyboard view + app->hid_numpad = hid_numpad_alloc(app); + view_set_previous_callback(hid_numpad_get_view(app->hid_numpad), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewNumpad, hid_numpad_get_view(app->hid_numpad)); + // Media view app->hid_media = hid_media_alloc(app); view_set_previous_callback(hid_media_get_view(app->hid_media), hid_exit_confirm_view); @@ -240,6 +253,8 @@ void hid_free(Hid* app) { hid_keynote_vertical_free(app->hid_keynote_vertical); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); hid_keyboard_free(app->hid_keyboard); + view_dispatcher_remove_view(app->view_dispatcher, HidViewNumpad); + hid_numpad_free(app->hid_numpad); view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index be9176a28..3478a5194 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -19,6 +19,7 @@ #include "views/hid_keynote.h" #include "views/hid_keynote_vertical.h" #include "views/hid_keyboard.h" +#include "views/hid_numpad.h" #include "views/hid_media.h" #include "views/hid_mouse.h" #include "views/hid_mouse_jiggler.h" @@ -44,6 +45,7 @@ struct Hid { HidKeynote* hid_keynote; HidKeynoteVertical* hid_keynote_vertical; HidKeyboard* hid_keyboard; + HidNumpad* hid_numpad; HidMedia* hid_media; HidMouse* hid_mouse; HidMouseJiggler* hid_mouse_jiggler; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 81e8d6dbe..ec4d23ad9 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -3,6 +3,7 @@ typedef enum { HidViewKeynote, HidViewKeynoteVertical, HidViewKeyboard, + HidViewNumpad, HidViewMedia, HidViewMouse, HidViewMouseJiggler, diff --git a/applications/external/hid_app/views/hid_numpad.c b/applications/external/hid_app/views/hid_numpad.c new file mode 100644 index 000000000..d3b488801 --- /dev/null +++ b/applications/external/hid_app/views/hid_numpad.c @@ -0,0 +1,302 @@ +#include "hid_numpad.h" +#include +#include +#include +#include "../hid.h" +#include "hid_icons.h" + +#define TAG "HidNumpad" + +struct HidNumpad { + View* view; + Hid* hid; +}; + +typedef struct { + uint8_t last_x; + uint8_t last_y; + uint8_t x; + uint8_t y; + uint8_t last_key_code; + uint16_t modifier_code; + bool ok_pressed; + bool back_pressed; + bool connected; + char key_string[5]; + HidTransport transport; +} HidNumpadModel; + +typedef struct { + uint8_t width; + char* key; + uint8_t height; + const Icon* icon; + uint8_t value; +} HidNumpadKey; + +typedef struct { + int8_t x; + int8_t y; +} HidNumpadPoint; + +#define MARGIN_TOP 0 +#define MARGIN_LEFT 24 +#define KEY_WIDTH 20 +#define KEY_HEIGHT 15 +#define KEY_PADDING 1 +#define ROW_COUNT 5 +#define COLUMN_COUNT 4 + +const HidNumpadKey hid_numpad_keyset[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .height = 1, .icon = NULL, .key = "NL", .value = HID_KEYPAD_NUMLOCK}, + {.width = 1, .height = 1, .icon = NULL, .key = "/", .value = HID_KEYPAD_SLASH}, + {.width = 1, .height = 1, .icon = NULL, .key = "*", .value = HID_KEYPAD_ASTERISK}, + {.width = 1, .height = 1, .icon = NULL, .key = "-", .value = HID_KEYPAD_MINUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "7", .value = HID_KEYPAD_7}, + {.width = 1, .height = 1, .icon = NULL, .key = "8", .value = HID_KEYBOARD_8}, + {.width = 1, .height = 1, .icon = NULL, .key = "9", .value = HID_KEYBOARD_9}, + {.width = 1, .height = 2, .icon = NULL, .key = "+", .value = HID_KEYPAD_PLUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "4", .value = HID_KEYPAD_4}, + {.width = 1, .height = 1, .icon = NULL, .key = "5", .value = HID_KEYPAD_5}, + {.width = 1, .height = 1, .icon = NULL, .key = "6", .value = HID_KEYPAD_6}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "1", .value = HID_KEYPAD_1}, + {.width = 1, .height = 1, .icon = NULL, .key = "2", .value = HID_KEYPAD_2}, + {.width = 1, .height = 1, .icon = NULL, .key = "3", .value = HID_KEYPAD_3}, + {.width = 1, .height = 2, .icon = NULL, .key = "En", .value = HID_KEYPAD_ENTER}, + }, + { + {.width = 2, .height = 1, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 0, .height = 0, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 1, .height = 1, .icon = NULL, .key = ".", .value = HID_KEYPAD_DOT}, + }, +}; + +static void hid_numpad_draw_key( + Canvas* canvas, + HidNumpadModel* model, + uint8_t x, + uint8_t y, + HidNumpadKey key, + bool selected) { + if(!key.width || !key.height) return; + + canvas_set_color(canvas, ColorBlack); + uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); + uint8_t keyHeight = KEY_HEIGHT * key.height + KEY_PADDING * (key.height - 1); + if(selected) { + elements_slightly_rounded_box( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + canvas_set_color(canvas, ColorWhite); + } else { + elements_slightly_rounded_frame( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + } + if(key.icon != NULL) { + canvas_draw_icon( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 - key.icon->height / 2, + key.icon); + } else { + strcpy(model->key_string, key.key); + canvas_draw_str_aligned( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 + 1, + AlignCenter, + AlignCenter, + model->key_string); + } +} + +static void hid_numpad_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidNumpadModel* model = context; + + if((!model->connected) && (model->transport == HidTransportBle)) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Numpad"); + + canvas_draw_icon(canvas, 68, 3, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 127, 4, AlignRight, AlignTop, "Hold to exit"); + + elements_multiline_text_aligned( + canvas, 4, 60, AlignLeft, AlignBottom, "Waiting for Connection..."); + return; + } + + canvas_set_font(canvas, FontKeyboard); + uint8_t initY = model->y == 0 ? 0 : 1; + + if(model->y > 5) { + initY = model->y - 4; + } + + for(uint8_t y = initY; y < ROW_COUNT; y++) { + const HidNumpadKey* numpadKeyRow = hid_numpad_keyset[y]; + uint8_t x = 0; + for(uint8_t i = 0; i < COLUMN_COUNT; i++) { + HidNumpadKey key = numpadKeyRow[i]; + bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; + bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; + hid_numpad_draw_key( + canvas, + model, + x, + y - initY, + key, + (!model->ok_pressed && keySelected) || backSelected); + x += key.width; + } + } +} + +static uint8_t hid_numpad_get_selected_key(HidNumpadModel* model) { + HidNumpadKey key = hid_numpad_keyset[model->y][model->x]; + return key.value; +} + +static void hid_numpad_get_select_key(HidNumpadModel* model, HidNumpadPoint delta) { + do { + const int delta_sum = model->y + delta.y; + model->y = delta_sum < 0 ? ROW_COUNT - 1 : delta_sum % ROW_COUNT; + } while(delta.y != 0 && hid_numpad_keyset[model->y][model->x].value == 0); + + do { + const int delta_sum = model->x + delta.x; + model->x = delta_sum < 0 ? COLUMN_COUNT - 1 : delta_sum % COLUMN_COUNT; + } while(delta.x != 0 && hid_numpad_keyset[model->y][model->x].width == 0); +} + +static void hid_numpad_process(HidNumpad* hid_numpad, InputEvent* event) { + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + if(event->key == InputKeyOk) { + if(event->type == InputTypePress) { + model->ok_pressed = true; + } else if(event->type == InputTypeLong || event->type == InputTypeShort) { + model->last_key_code = hid_numpad_get_selected_key(model); + hid_hal_keyboard_press( + hid_numpad->hid, model->modifier_code | model->last_key_code); + } else if(event->type == InputTypeRelease) { + hid_hal_keyboard_release( + hid_numpad->hid, model->modifier_code | model->last_key_code); + model->ok_pressed = false; + } + } else if(event->key == InputKeyBack) { + if(event->type == InputTypePress) { + model->back_pressed = true; + } else if(event->type == InputTypeShort) { + hid_hal_keyboard_press(hid_numpad->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_numpad->hid, HID_KEYBOARD_DELETE); + } else if(event->type == InputTypeRelease) { + model->back_pressed = false; + } + } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { + if(event->key == InputKeyUp) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = -1}); + } else if(event->key == InputKeyDown) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = 1}); + } else if(event->key == InputKeyLeft) { + if(model->last_x == 2 && model->last_y == 2 && model->y == 1 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else if( + model->last_x == 2 && model->last_y == 4 && model->y == 3 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = -1, .y = 0}); + model->last_x = 0; + model->last_y = 0; + } else if(event->key == InputKeyRight) { + if(model->x == 2 && model->y == 2) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else if(model->x == 2 && model->y == 4) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = 0}); + } + } + } + }, + true); +} + +static bool hid_numpad_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidNumpad* hid_numpad = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + hid_hal_keyboard_release_all(hid_numpad->hid); + } else { + hid_numpad_process(hid_numpad, event); + consumed = true; + } + + return consumed; +} + +HidNumpad* hid_numpad_alloc(Hid* bt_hid) { + HidNumpad* hid_numpad = malloc(sizeof(HidNumpad)); + hid_numpad->view = view_alloc(); + hid_numpad->hid = bt_hid; + view_set_context(hid_numpad->view, hid_numpad); + view_allocate_model(hid_numpad->view, ViewModelTypeLocking, sizeof(HidNumpadModel)); + view_set_draw_callback(hid_numpad->view, hid_numpad_draw_callback); + view_set_input_callback(hid_numpad->view, hid_numpad_input_callback); + + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + model->transport = bt_hid->transport; + model->y = 0; + }, + true); + + return hid_numpad; +} + +void hid_numpad_free(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + view_free(hid_numpad->view); + free(hid_numpad); +} + +View* hid_numpad_get_view(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + return hid_numpad->view; +} + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected) { + furi_assert(hid_numpad); + with_view_model( + hid_numpad->view, HidNumpadModel * model, { model->connected = connected; }, true); +} diff --git a/applications/external/hid_app/views/hid_numpad.h b/applications/external/hid_app/views/hid_numpad.h new file mode 100644 index 000000000..d9bf54df9 --- /dev/null +++ b/applications/external/hid_app/views/hid_numpad.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidNumpad HidNumpad; + +HidNumpad* hid_numpad_alloc(Hid* bt_hid); + +void hid_numpad_free(HidNumpad* hid_numpad); + +View* hid_numpad_get_view(HidNumpad* hid_numpad); + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected); From 8a5cef00795d02eaa5a892b708432f95164a1e22 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 19:56:06 +0100 Subject: [PATCH 089/216] Fix zero tracker app (revert "update") --- .../music_tracker/tracker_engine/speaker_hal.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/applications/external/music_tracker/tracker_engine/speaker_hal.c b/applications/external/music_tracker/tracker_engine/speaker_hal.c index 208fee04c..0a506a424 100644 --- a/applications/external/music_tracker/tracker_engine/speaker_hal.c +++ b/applications/external/music_tracker/tracker_engine/speaker_hal.c @@ -40,12 +40,17 @@ void tracker_speaker_stop() { } void tracker_speaker_init() { - furi_hal_speaker_start(200.0f, 0.01f); - tracker_speaker_stop(); + if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) { + furi_hal_speaker_start(200.0f, 0.01f); + tracker_speaker_stop(); + } } void tracker_speaker_deinit() { - furi_hal_speaker_stop(); + if(furi_hal_speaker_is_mine()) { + furi_hal_speaker_stop(); + furi_hal_speaker_release(); + } } static FuriHalInterruptISR tracker_isr; @@ -99,4 +104,4 @@ void tracker_debug_set(bool value) { void tracker_debug_deinit() { furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow); -} \ No newline at end of file +} From ae321fb5f4c616d3965546926b1b4b446eef8d86 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 20:40:23 +0100 Subject: [PATCH 090/216] Mfw NULL pointer dereference (fix IFTTT) --- .../external/ifttt/ifttt_virtual_button.c | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/applications/external/ifttt/ifttt_virtual_button.c b/applications/external/ifttt/ifttt_virtual_button.c index e23b8715d..d518a1109 100644 --- a/applications/external/ifttt/ifttt_virtual_button.c +++ b/applications/external/ifttt/ifttt_virtual_button.c @@ -38,6 +38,11 @@ void save_settings_file(FlipperFormat* file, Settings* settings) { Settings* load_settings() { Settings* settings = malloc(sizeof(Settings)); + settings->save_ssid = ""; + settings->save_password = ""; + settings->save_key = ""; + settings->save_event = ""; + Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); @@ -53,29 +58,14 @@ Settings* load_settings() { text_event_value = furi_string_alloc(); if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) != FSE_OK) { - if(!flipper_format_file_open_new(file, CONFIG_FILE_PATH)) { - flipper_format_file_close(file); - } else { - settings->save_ssid = malloc(1); - settings->save_password = malloc(1); - settings->save_key = malloc(1); - settings->save_event = malloc(1); - - settings->save_ssid[0] = '\0'; - settings->save_password[0] = '\0'; - settings->save_key[0] = '\0'; - settings->save_event[0] = '\0'; - + if(flipper_format_file_open_new(file, CONFIG_FILE_PATH)) { save_settings_file(file, settings); - flipper_format_file_close(file); } + flipper_format_file_close(file); } else { - if(!flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { - flipper_format_file_close(file); - } else { + if(flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { uint32_t value; - if(!flipper_format_read_header(file, string_value, &value)) { - } else { + if(flipper_format_read_header(file, string_value, &value)) { if(flipper_format_read_string(file, CONF_SSID, text_ssid_value)) { settings->save_ssid = malloc(furi_string_size(text_ssid_value) + 1); strcpy(settings->save_ssid, furi_string_get_cstr(text_ssid_value)); @@ -93,8 +83,8 @@ Settings* load_settings() { strcpy(settings->save_event, furi_string_get_cstr(text_event_value)); } } - flipper_format_file_close(file); } + flipper_format_file_close(file); } furi_string_free(text_ssid_value); @@ -248,4 +238,4 @@ int32_t ifttt_virtual_button_app(void* p) { view_dispatcher_run(app->view_dispatcher); ifttt_virtual_button_app_free(app); return 0; -} \ No newline at end of file +} From 259855e7885ce9d7866fbe0b907313edba260cee Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:52:41 +0100 Subject: [PATCH 091/216] Updated ac.ir New additions --- assets/resources/infrared/assets/ac.ir | 34 ++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 49a4acd20..777d5399c 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: raw @@ -1740,3 +1740,33 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 00 00 00 00 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 443 457 418 451 424 445 420 449 416 453 422 25403 3487 1758 421 1325 416 445 420 452 423 446 419 1319 422 447 418 450 415 456 419 449 416 1323 418 454 421 1316 414 1326 415 462 424 1307 423 1315 415 1323 418 1322 419 1321 420 449 416 452 423 1316 414 455 420 448 417 453 422 447 418 452 423 448 417 451 424 443 422 450 415 452 423 445 420 450 415 456 419 450 415 452 423 447 418 450 415 456 419 1318 423 447 418 454 421 445 420 450 415 453 422 446 419 451 424 1315 415 1324 417 454 421 446 419 1321 420 1319 422 448 417 452 423 445 420 449 416 453 422 448 417 452 423 445 420 449 416 455 420 1319 422 1314 416 1325 416 1322 419 1322 419 1318 423 1317 424 447 418 1320 421 1317 424 1317 424 1315 415 455 420 449 416 452 423 447 418 451 414 454 421 448 417 453 422 448 417 452 423 444 421 449 416 452 423 447 418 453 422 445 420 450 415 456 419 448 417 453 422 446 419 450 415 455 420 450 415 453 422 448 417 452 423 444 421 448 417 454 421 446 419 452 423 445 420 450 415 453 422 447 418 451 424 446 419 449 416 454 421 447 418 452 423 446 419 452 423 1315 415 451 424 1316 414 456 419 451 414 453 422 1317 424 1316 425 444 421 447 418 452 423 448 417 450 415 455 420 456 419 449 416 446 419 451 414 455 420 1320 421 447 418 452 423 453 422 439 415 1324 417 459 416 446 419 451 424 446 419 1320 421 446 419 1319 422 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 444 455 420 449 416 454 421 448 417 451 424 25402 3487 1758 421 1317 424 445 420 452 423 443 422 1317 424 447 418 451 424 447 418 449 416 1324 417 452 423 1315 415 1324 417 452 423 1316 425 1315 415 1325 416 1323 418 1319 422 449 416 452 423 1318 423 445 420 448 417 453 422 447 418 452 423 446 419 449 416 455 420 447 418 453 422 446 419 452 423 446 419 451 424 444 421 447 418 451 424 445 420 1320 421 448 417 454 421 445 420 452 423 445 420 450 415 454 421 1316 414 1324 417 454 421 448 417 1321 420 1320 421 448 417 453 422 446 419 452 423 446 419 449 416 455 420 448 417 451 424 445 420 1321 420 1319 422 1316 414 1324 417 1324 417 1321 420 1320 421 449 416 1323 418 1323 418 1319 422 1317 424 446 419 453 422 445 420 450 415 453 422 448 417 452 423 447 418 450 415 455 420 448 417 454 421 445 420 451 414 455 420 449 416 454 421 448 417 452 423 446 419 449 416 454 421 447 418 452 423 445 420 450 415 454 421 450 415 454 421 447 418 452 423 444 421 451 424 442 423 449 416 451 424 445 420 450 415 455 420 448 417 454 421 447 418 450 415 457 418 1317 424 448 417 1320 421 448 417 453 422 449 416 1321 420 1320 421 448 417 452 423 449 416 451 424 446 419 448 417 454 421 449 416 452 423 447 418 452 423 1315 415 452 423 447 418 451 424 446 419 1319 422 448 417 451 424 446 419 449 416 1324 417 453 422 1316 414 +# SWING_HORIZONTAL +name: SWING +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 446 455 420 449 416 461 393 467 419 454 421 25402 3484 1759 419 1319 422 449 416 454 421 447 418 1322 419 449 416 454 421 449 416 452 423 1317 424 444 421 1321 420 1316 425 446 419 1329 422 1308 422 1318 422 1317 424 1314 416 453 422 447 418 1323 418 451 424 444 421 448 417 454 421 449 416 458 417 444 421 449 416 454 421 447 418 453 422 446 419 456 419 445 420 448 417 452 423 446 419 451 424 1316 414 453 422 447 418 453 422 446 419 451 414 455 420 449 416 1324 417 1321 420 452 423 444 421 1318 423 1317 423 445 420 450 415 455 420 447 418 455 420 447 418 451 424 445 420 456 419 444 421 1317 424 1316 424 1315 415 1323 417 452 423 1316 414 456 419 1318 423 448 417 452 423 444 421 450 415 456 419 448 417 453 422 447 418 450 415 454 421 448 417 454 421 446 419 452 423 446 419 449 416 455 420 448 417 452 423 448 417 451 424 451 424 445 420 444 421 447 418 460 415 446 419 451 424 446 419 450 415 454 421 449 416 1321 420 451 424 444 421 449 416 453 422 447 418 454 421 445 420 449 416 456 419 449 416 452 423 447 418 451 424 444 421 451 424 1314 416 453 422 1324 417 445 420 449 416 453 422 1319 422 1315 415 455 420 448 417 452 423 453 422 442 423 451 424 439 415 454 421 447 418 451 424 447 418 1322 418 451 424 442 423 448 417 451 424 1317 423 1315 415 454 421 449 416 460 415 446 419 1320 421 1319 422 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 445 455 421 449 416 453 422 447 418 451 424 25400 3494 1753 416 1322 419 450 415 456 420 449 416 1325 416 451 425 444 421 448 417 453 423 1318 423 444 421 1320 421 1316 414 457 419 1320 421 1318 423 1314 417 1322 419 1320 421 449 416 453 422 1317 424 445 420 450 415 456 419 447 418 451 414 456 420 449 416 452 424 448 417 453 422 445 420 450 415 456 419 448 417 452 423 447 418 449 416 453 423 448 417 453 423 446 419 449 416 453 423 447 418 1321 420 451 414 454 422 449 416 1322 419 1319 422 449 416 1322 419 451 424 445 420 449 416 455 421 445 420 449 416 455 420 448 417 452 424 446 419 1321 420 1317 424 1315 416 1324 417 1322 419 1320 421 1320 421 446 419 1319 422 1319 422 1318 423 1313 417 453 423 445 420 450 415 454 421 449 416 454 422 446 419 449 416 456 420 448 417 453 423 444 421 450 415 454 422 447 418 451 424 445 420 450 415 455 420 447 418 452 424 447 418 451 424 445 420 448 417 453 423 446 419 451 424 444 421 448 417 452 423 446 419 451 424 445 420 448 417 451 414 456 420 452 424 443 422 449 416 451 424 448 417 449 416 455 420 1318 423 446 419 1319 422 448 417 451 424 447 418 1320 421 1316 415 455 421 451 414 455 421 449 416 451 424 446 419 1319 422 448 417 454 422 446 419 451 414 1325 416 452 423 447 418 451 424 447 418 1318 423 446 419 449 416 1327 424 1312 419 449 416 455 421 449 416 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 645 17766 3059 8884 533 461 557 1427 560 435 584 433 534 458 534 458 534 458 588 404 587 405 586 1399 586 407 584 408 558 1429 555 1457 502 491 525 1460 528 1458 554 1431 554 1431 555 1431 554 438 555 438 554 439 553 440 553 464 528 464 528 464 529 465 528 465 526 467 526 467 527 465 553 439 554 439 554 438 554 439 554 439 553 439 554 439 553 439 553 439 554 440 552 464 528 464 528 465 528 466 527 466 501 492 525 468 526 466 527 466 553 439 554 439 553 440 552 1433 553 1433 553 2936 3024 8893 552 1458 527 465 528 465 527 467 526 467 500 493 524 468 526 467 526 467 552 1434 552 441 552 441 552 1435 550 465 528 1458 527 1458 528 1459 527 1485 501 1485 500 1486 501 491 527 466 528 465 528 465 527 465 528 465 527 465 528 465 528 465 527 465 528 465 527 466 527 466 527 492 500 492 501 492 500 493 500 493 500 492 526 466 527 465 527 465 527 465 527 466 527 466 527 466 527 465 527 466 526 466 527 466 526 467 526 493 499 493 474 518 499 494 500 493 526 2936 3025 8918 526 1459 527 466 527 466 527 466 526 466 527 466 526 467 526 467 525 467 526 1460 525 493 499 493 498 495 498 495 499 493 500 493 525 1460 527 1460 525 1460 526 1460 525 1460 526 1460 526 468 525 1487 499 1487 497 495 498 495 499 493 500 1486 525 1460 525 1460 525 467 525 467 526 467 525 467 526 468 524 1462 524 468 524 494 498 1488 497 1488 499 494 499 493 525 468 525 1461 524 468 525 468 524 468 525 468 525 468 524 468 525 469 524 494 498 494 499 1488 473 1514 524 From bf0e8534132794962a21e54b734567704166d175 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:53:25 +0100 Subject: [PATCH 092/216] Updated audio.ir Updated last checked, no new additions --- assets/resources/infrared/assets/audio.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index f6183ed86..ce6d0a7aa 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: parsed From 7ba96ad653197f9f98c367f829b67f0471657d0e Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:53:48 +0100 Subject: [PATCH 093/216] Updated fans.ir New additions --- assets/resources/infrared/assets/fans.ir | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index 6bef11b34..e422bdce4 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: raw @@ -1497,3 +1497,9 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3534 3439 954 2505 985 2535 955 798 954 2535 899 2591 899 2599 899 853 925 2566 924 2567 922 2596 894 2596 894 867 894 859 894 860 893 2597 894 859 894 859 894 867 894 2597 893 859 894 859 894 860 893 859 894 2605 894 40336 3531 3469 894 2597 893 2597 893 859 894 2597 893 2597 893 2605 893 860 893 2597 893 2597 893 2597 894 2597 893 868 893 860 893 860 893 2597 893 860 893 860 893 868 893 2597 893 860 893 860 893 860 893 860 893 2605 893 +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 1A 00 00 00 From 79566b7fa31a1cef5465b4f5ffc1369cb40dd36b Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 20:54:15 +0100 Subject: [PATCH 094/216] Updated projectors.ir New additions --- .../resources/infrared/assets/projectors.ir | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 00e331bd4..8e81a25bd 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # # ON name: POWER @@ -886,3 +886,27 @@ type: parsed protocol: NECext address: 84 F4 00 00 command: 2F D0 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 4F 50 00 00 +command: 0F F0 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 12 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 06 00 00 00 +# +name: VOL+ +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 00 00 00 00 From dd6c031a3186dda25f92c5ea27a8053bb5a36451 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 2 May 2023 21:00:24 +0100 Subject: [PATCH 095/216] Updated tv.ir New additions, Added full sharp tv support. Reverted Vizio raw data change, will add this if needed --- assets/resources/infrared/assets/tv.ir | 68 ++++++++++++++++++++------ 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index bd246f3d6..8c781eea9 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 2, May, 2023 -# Last Checked 2, May, 2023 +# Last Updated 2nd May, 2023 +# Last Checked 2nd May, 2023 # name: POWER type: parsed @@ -1899,39 +1899,77 @@ type: parsed protocol: SIRC20 address: 10 01 00 00 command: 33 00 00 00 +# +# Sharp TV # name: POWER +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 01 FE 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 0C F3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 10 EF 00 00 +# +name: CH+ +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 18 E7 00 00 +# +name: CH- +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 1C E3 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 00 BD 00 00 +command: 04 FB 00 00 +# +name: POWER type: raw frequency: 38000 duty_cycle: 0.330000 -data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274 +data: 278 1811 277 788 246 794 250 764 280 786 248 792 252 1813 275 1815 273 791 253 1812 276 789 255 785 249 791 253 1812 276 789 255 45322 280 1809 279 786 248 766 278 788 246 794 250 1815 273 792 252 788 246 1819 280 785 249 1817 271 1819 280 1810 278 787 247 1818 281 43217 274 1818 270 794 250 764 280 786 248 792 252 788 256 1809 279 1811 277 788 246 1819 280 785 249 766 278 762 272 1819 280 785 248 # name: MUTE type: raw frequency: 38000 duty_cycle: 0.330000 -data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274 -# -name: POWER -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631 +data: 278 1812 276 762 282 758 276 765 279 761 273 1818 281 1809 279 1811 277 762 282 1809 279 760 274 766 278 762 282 1809 279 760 274 44279 276 1813 275 763 281 759 275 766 278 762 272 768 276 764 280 760 274 1817 271 768 276 1815 273 1817 271 1819 280 759 275 1816 272 44276 279 1812 276 763 281 758 276 765 279 761 273 1818 281 1810 278 1811 277 762 272 1819 279 760 274 766 278 762 282 1809 279 760 274 # name: VOL+ type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655 -# +data: 272 1817 271 794 250 790 254 786 248 792 252 762 272 794 250 1815 273 792 252 1813 275 790 254 785 249 766 278 1813 275 789 255 46372 273 1817 271 794 250 763 281 785 248 792 252 1813 275 1814 274 791 253 1812 276 789 255 1810 278 1812 276 1813 275 790 254 1811 277 42170 277 1814 274 791 253 787 247 793 251 763 281 759 275 791 253 1812 276 789 255 1810 278 787 247 793 251 789 255 1810 278 787 247 +# name: VOL- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656 +data: 275 1814 274 791 253 787 247 793 251 789 255 1810 278 787 247 1818 281 785 249 1816 272 793 251 789 255 785 249 1816 272 766 278 45325 274 1815 273 792 252 762 272 794 250 790 254 786 247 1818 270 794 250 1815 273 792 252 1813 275 1815 273 1816 272 793 251 1814 274 43224 277 1814 274 764 280 786 248 792 252 788 246 1820 279 786 247 1817 271 768 276 1815 273 792 252 761 273 794 250 1815 273 791 253 # -name: MUTE +name: CH+ type: raw frequency: 38000 duty_cycle: 0.330000 -data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655 +data: 272 1817 271 794 250 790 254 786 248 792 252 1813 275 790 254 759 275 792 252 1813 275 789 255 785 248 792 252 1813 275 789 255 46372 273 1817 271 793 251 763 281 759 275 791 253 787 247 1818 281 1810 278 1812 276 789 255 1809 279 1811 277 1813 275 790 254 1811 277 42169 277 1815 273 792 252 787 247 794 250 789 255 1810 278 787 247 794 250 789 255 1810 278 761 273 793 251 789 255 1810 278 787 247 +# +name: CH- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 273 1816 272 767 277 789 255 785 249 791 253 787 246 1818 281 785 248 765 279 1812 276 789 255 759 275 791 253 1812 276 789 255 46372 281 1808 280 785 249 791 253 787 247 793 251 1814 274 791 253 1812 276 1814 274 791 253 1812 276 1814 274 1815 273 792 252 1813 275 42172 272 1819 280 785 249 765 279 761 273 768 276 764 280 1811 277 788 246 768 276 1815 273 792 252 788 246 794 250 1815 273 791 253 From 5d62ce919bf47a74a50aa421b6936809f2bfbc54 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 21:29:46 +0100 Subject: [PATCH 096/216] :doomed: --- .../services/storage/storages/storage_int.c | 92 +++++++++---------- firmware/targets/f7/src/recovery.c | 1 - 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index 8e4e2b0fc..5342c2bdd 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -194,41 +194,41 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { if(need_format) { // Backup U2F keys - lfs_file_t file; - uint8_t* cnt = NULL; - uint32_t cnt_size; - uint8_t* key = NULL; - uint32_t key_size; - if(lfs_mount(lfs, &lfs_data->config) == 0) { - FURI_LOG_I(TAG, "Factory reset: Mounted for backup"); + // lfs_file_t file; + // uint8_t* cnt = NULL; + // uint32_t cnt_size; + // uint8_t* key = NULL; + // uint32_t key_size; + // if(lfs_mount(lfs, &lfs_data->config) == 0) { + // FURI_LOG_I(TAG, "Factory reset: Mounted for backup"); - if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_RDONLY) == 0) { - cnt_size = file.ctz.size; - cnt = malloc(cnt_size); - if(lfs_file_read(lfs, &file, cnt, cnt_size) != (int32_t)cnt_size) { - free(cnt); - cnt = NULL; - } - lfs_file_close(lfs, &file); - if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_RDONLY) == 0) { - key_size = file.ctz.size; - key = malloc(key_size); - if(lfs_file_read(lfs, &file, key, key_size) != (int32_t)key_size) { - free(key); - key = NULL; - } - lfs_file_close(lfs, &file); - } - } + // if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_RDONLY) == 0) { + // cnt_size = file.ctz.size; + // cnt = malloc(cnt_size); + // if(lfs_file_read(lfs, &file, cnt, cnt_size) != (int32_t)cnt_size) { + // free(cnt); + // cnt = NULL; + // } + // lfs_file_close(lfs, &file); + // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_RDONLY) == 0) { + // key_size = file.ctz.size; + // key = malloc(key_size); + // if(lfs_file_read(lfs, &file, key, key_size) != (int32_t)key_size) { + // free(key); + // key = NULL; + // } + // lfs_file_close(lfs, &file); + // } + // } - if(lfs_unmount(lfs) == 0) { - FURI_LOG_E(TAG, "Factory reset: Unmounted after backup"); - } else { - FURI_LOG_E(TAG, "Factory reset: Unmount after backup failed"); - } - } else { - FURI_LOG_E(TAG, "Factory reset: Mount for backup failed"); - } + // if(lfs_unmount(lfs) == 0) { + // FURI_LOG_E(TAG, "Factory reset: Unmounted after backup"); + // } else { + // FURI_LOG_E(TAG, "Factory reset: Unmount after backup failed"); + // } + // } else { + // FURI_LOG_E(TAG, "Factory reset: Mount for backup failed"); + // } // Format storage if(lfs_format(lfs, &lfs_data->config) == 0) { @@ -239,19 +239,19 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { storage->status = StorageStatusOK; // Restore U2F keys - if(cnt != NULL && key != NULL) { - if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_WRONLY | LFS_O_CREAT) == 0) { - lfs_file_write(lfs, &file, cnt, cnt_size); - lfs_file_close(lfs, &file); - if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_WRONLY | LFS_O_CREAT) == - 0) { - lfs_file_write(lfs, &file, key, key_size); - lfs_file_close(lfs, &file); - } - } - } - if(cnt != NULL) free(cnt); - if(key != NULL) free(key); + // if(cnt != NULL && key != NULL) { + // if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_WRONLY | LFS_O_CREAT) == 0) { + // lfs_file_write(lfs, &file, cnt, cnt_size); + // lfs_file_close(lfs, &file); + // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_WRONLY | LFS_O_CREAT) == + // 0) { + // lfs_file_write(lfs, &file, key, key_size); + // lfs_file_close(lfs, &file); + // } + // } + // } + // if(cnt != NULL) free(cnt); + // if(key != NULL) free(key); } else { FURI_LOG_E(TAG, "Factory reset: Mount after format failed"); storage->status = StorageStatusNotMounted; diff --git a/firmware/targets/f7/src/recovery.c b/firmware/targets/f7/src/recovery.c index 700fb03c6..f1bfe5383 100644 --- a/firmware/targets/f7/src/recovery.c +++ b/firmware/targets/f7/src/recovery.c @@ -57,7 +57,6 @@ void flipper_boot_recovery_exec() { if(!counter) { furi_hal_rtc_set_flag(FuriHalRtcFlagResetPin); - furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_set_pin_fails(0); furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); } From 331f26547bdbf7fab2ec96fe8741693f628ca635 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 22:54:32 +0100 Subject: [PATCH 097/216] Add XTREME_SETTINGS_WAIT() for race conditions --- firmware/targets/f7/api_symbols.csv | 1 + lib/xtreme/settings.c | 14 +++++++++++++- lib/xtreme/xtreme.h | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 784be14a9..2ccfe3ed5 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -323,6 +323,7 @@ Function,-,SystemInit,void, Function,+,XTREME_ASSETS,XtremeAssets*, Function,+,XTREME_SETTINGS,XtremeSettings*, Function,+,XTREME_SETTINGS_SAVE,void, +Function,+,XTREME_SETTINGS_WAIT,XtremeSettings*, Function,-,_Exit,void,int Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" diff --git a/lib/xtreme/settings.c b/lib/xtreme/settings.c index fe6520808..88aa55b99 100644 --- a/lib/xtreme/settings.c +++ b/lib/xtreme/settings.c @@ -6,6 +6,7 @@ #define TAG "XtremeSettings" XtremeSettings xtreme_settings = { + .loaded = false, .asset_pack = "", .anim_speed = 100, // 100% .cycle_anims = 0, // Meta.txt @@ -27,7 +28,7 @@ XtremeSettings xtreme_settings = { .favorite_timeout = 0, // OFF .bad_bt = false, // USB .bad_bt_remember = false, // OFF - .butthurt_timer = 43200, // 12 H + .butthurt_timer = 21600, // 6 H .rgb_backlight = false, // OFF }; @@ -88,6 +89,8 @@ void XTREME_SETTINGS_LOAD() { } flipper_format_free(file); furi_record_close(RECORD_STORAGE); + + xtreme_settings.loaded = true; } void XTREME_SETTINGS_SAVE() { @@ -128,3 +131,12 @@ void XTREME_SETTINGS_SAVE() { XtremeSettings* XTREME_SETTINGS() { return &xtreme_settings; } + +XtremeSettings* XTREME_SETTINGS_WAIT() { + if(furi_hal_is_normal_boot()) { + while(!xtreme_settings.loaded) { + furi_delay_ms(50); + } + } + return &xtreme_settings; +} diff --git a/lib/xtreme/xtreme.h b/lib/xtreme/xtreme.h index 54c208ae7..1e63f10ec 100644 --- a/lib/xtreme/xtreme.h +++ b/lib/xtreme/xtreme.h @@ -13,6 +13,7 @@ extern "C" { #define XTREME_ASSETS_PACK_NAME_LEN 32 typedef struct { + bool loaded; char asset_pack[XTREME_ASSETS_PACK_NAME_LEN]; uint32_t anim_speed; int32_t cycle_anims; @@ -38,8 +39,9 @@ typedef struct { bool rgb_backlight; } XtremeSettings; -XtremeSettings* XTREME_SETTINGS(); void XTREME_SETTINGS_SAVE(); +XtremeSettings* XTREME_SETTINGS(); +XtremeSettings* XTREME_SETTINGS_WAIT(); typedef struct { bool is_nsfw; From d4eef8e3f860566515386dce796ce3eb9282bed3 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 22:55:06 +0100 Subject: [PATCH 098/216] Properly read butthurt timer setting --- applications/services/dolphin/dolphin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 5e5ff07d3..145224542 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -80,7 +80,7 @@ Dolphin* dolphin_alloc() { dolphin->state = dolphin_state_alloc(); dolphin->event_queue = furi_message_queue_alloc(8, sizeof(DolphinEvent)); dolphin->pubsub = furi_pubsub_alloc(); - int32_t butthurt = XTREME_SETTINGS()->butthurt_timer; + int32_t butthurt = XTREME_SETTINGS_WAIT()->butthurt_timer; dolphin->butthurt_timer = xTimerCreate( NULL, (butthurt > 0) ? (butthurt * 1000) : -1, From 238005890ec6a619157ac75eb60bd02dfe6c736e Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 3 May 2023 00:56:25 +0300 Subject: [PATCH 099/216] [FL-3294] Fix TERMINFO on Linux systems (#2630) * Fix TERMINFO on Linux systems * Set TERMINFO_DIRS only on Linux * Unset TERMINFO_DIRS if it was not set before --- scripts/toolchain/fbtenv.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 57a50281e..143dce74b 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -56,6 +56,16 @@ fbtenv_restore_env() unset SSL_CERT_FILE; unset REQUESTS_CA_BUNDLE; fi + + if [ "$SYS_TYPE" = "Linux" ]; then + if [ -n "$SAVED_TERMINFO_DIRS" ]; then + export TERMINFO_DIRS="$SAVED_TERMINFO_DIRS"; + else + unset TERMINFO_DIRS; + fi + unset SAVED_TERMINFO_DIRS; + fi + export PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; export PYTHONPATH="$SAVED_PYTHONPATH"; export PYTHONHOME="$SAVED_PYTHONHOME"; @@ -325,6 +335,11 @@ fbtenv_main() export PYTHONNOUSERSITE=1; export PYTHONPATH=; export PYTHONHOME=; + + if [ "$SYS_TYPE" = "Linux" ]; then + export SAVED_TERMINFO_DIRS="${TERMINFO_DIRS:-""}"; + export TERMINFO_DIRS="$TOOLCHAIN_ARCH_DIR/ncurses/share/terminfo"; + fi } fbtenv_main "${1:-""}"; From f2f46e42f616b3ff0437a643f29cccfaf2a676d6 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 2 May 2023 22:59:19 +0100 Subject: [PATCH 100/216] Bump v45 --- fbt_options.py | 2 +- scripts/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fbt_options.py b/fbt_options.py index 0e87521a1..5c874357a 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -14,7 +14,7 @@ DEBUG = 0 # Suffix to add to files when building distribution # If OS environment has DIST_SUFFIX set, it will be used instead -DIST_SUFFIX = "XFW-0044_09042023" +DIST_SUFFIX = "XFW-0045_02052023" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" diff --git a/scripts/version.py b/scripts/version.py index 4fd5fd3f9..6011dea26 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,5 +1,5 @@ #!/usb/bin/env python3 -VERSION = "XFW-0044" +VERSION = "XFW-0045" from flipper.app import App From b5dc2f239e3e7c92080c4c29e9ab8627209622d1 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 00:11:40 +0100 Subject: [PATCH 101/216] Asset pack support status bar background --- applications/main/archive/views/archive_browser_view.c | 2 +- applications/services/gui/gui.c | 2 +- lib/xtreme/assets.c | 2 ++ lib/xtreme/xtreme.h | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 6e42cb40b..cc2ed6263 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -324,7 +324,7 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m const char* tab_name = ArchiveTabNames[model->tab_idx]; - canvas_draw_icon(canvas, 0, 0, &I_Background_128x11); + canvas_draw_icon(canvas, 0, 0, XTREME_ASSETS()->I_Background_128x11); canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 0, 0, 50, 13); diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index e914e807f..8f0deaa6f 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -75,7 +75,7 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { canvas_draw_box(gui->canvas, 89, 3, 38, 6); canvas_set_color(gui->canvas, ColorBlack); canvas_set_bitmap_mode(gui->canvas, 1); - canvas_draw_icon(gui->canvas, 0, 0, &I_Background_128x11); + canvas_draw_icon(gui->canvas, 0, 0, XTREME_ASSETS()->I_Background_128x11); } else { canvas_set_color(gui->canvas, ColorBlack); } diff --git a/lib/xtreme/assets.c b/lib/xtreme/assets.c index 3c27f838c..cc1a6fe0d 100644 --- a/lib/xtreme/assets.c +++ b/lib/xtreme/assets.c @@ -28,6 +28,7 @@ XtremeAssets xtreme_assets = { .I_RFIDDolphinSend_97x61 = &I_RFIDDolphinSend_97x61, .I_RFIDDolphinSuccess_108x57 = &I_RFIDDolphinSuccess_108x57, .I_Cry_dolph_55x52 = &I_Cry_dolph_55x52, + .I_Background_128x11 = &I_Background_128x11, .I_Fishing_123x52 = &I_Fishing_123x52, .I_Scanning_123x52 = &I_Scanning_123x52, .I_Auth_62x31 = &I_Auth_62x31, @@ -132,6 +133,7 @@ void swap(XtremeAssets* x, FuriString* p, File* f) { icon(&x->I_RFIDDolphinSend_97x61, "RFID/RFIDDolphinSend_97x61", p, f); icon(&x->I_RFIDDolphinSuccess_108x57, "RFID/RFIDDolphinSuccess_108x57", p, f); icon(&x->I_Cry_dolph_55x52, "Settings/Cry_dolph_55x52", p, f); + icon(&x->I_Background_128x11, "StatusBar/Background_128x11", p, f); icon(&x->I_Fishing_123x52, "SubGhz/Fishing_123x52", p, f); icon(&x->I_Scanning_123x52, "SubGhz/Scanning_123x52", p, f); icon(&x->I_Auth_62x31, "U2F/Auth_62x31", p, f); diff --git a/lib/xtreme/xtreme.h b/lib/xtreme/xtreme.h index 1e63f10ec..e4baeeeba 100644 --- a/lib/xtreme/xtreme.h +++ b/lib/xtreme/xtreme.h @@ -64,6 +64,7 @@ typedef struct { const Icon* I_RFIDDolphinSend_97x61; const Icon* I_RFIDDolphinSuccess_108x57; const Icon* I_Cry_dolph_55x52; + const Icon* I_Background_128x11; const Icon* I_Fishing_123x52; const Icon* I_Scanning_123x52; const Icon* I_Auth_62x31; From e37dedd477a18edc99201277f98472c3c12e617b Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 00:36:54 +0100 Subject: [PATCH 102/216] Fix some memory management bugs in apps --- applications/external/flipfrid/flipfrid.c | 3 --- applications/external/ibtn_fuzzer/ibtnfuzzer.c | 3 --- .../wifi_marauder_companion/wifi_marauder_text_input.c | 9 --------- applications/external/wiiec/wii_anal.c | 6 +++--- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/applications/external/flipfrid/flipfrid.c b/applications/external/flipfrid/flipfrid.c index 25bdac024..172a98ef3 100644 --- a/applications/external/flipfrid/flipfrid.c +++ b/applications/external/flipfrid/flipfrid.c @@ -121,9 +121,6 @@ void flipfrid_free(FlipFridState* flipfrid) { furi_string_free(flipfrid->main_menu_proto_items[i]); } - free(flipfrid->data); - free(flipfrid->payload); - // The rest free(flipfrid); } diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.c b/applications/external/ibtn_fuzzer/ibtnfuzzer.c index 880d3983b..9e6239b69 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.c +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.c @@ -121,9 +121,6 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) { furi_string_free(ibtnfuzzer->main_menu_proto_items[i]); } - free(ibtnfuzzer->data); - free(ibtnfuzzer->payload); - // The rest free(ibtnfuzzer); } diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c index d9eee83c9..e17e5aaee 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c @@ -168,31 +168,22 @@ static char char_to_uppercase(const char letter) { switch(letter) { case '_': return 0x20; - break; case '(': return 0x29; - break; case '{': return 0x7d; - break; case '[': return 0x5d; - break; case '/': return 0x5c; - break; case ';': return 0x3a; - break; case '.': return 0x2c; - break; case '!': return 0x3f; - break; case '<': return 0x3e; - break; } if(char_is_lowercase(letter)) { return (letter - 0x20); diff --git a/applications/external/wiiec/wii_anal.c b/applications/external/wiiec/wii_anal.c index e3bb21f0f..5882dd60b 100644 --- a/applications/external/wiiec/wii_anal.c +++ b/applications/external/wiiec/wii_anal.c @@ -488,13 +488,13 @@ int32_t wii_ec_anal(void) { bail: // 10. Release system notification queue - if(state->notify) { + if(state && state->notify) { furi_record_close(RECORD_NOTIFICATION); state->notify = NULL; } // 9. Stop the timer - if(state->timer) { + if(state && state->timer) { (void)furi_timer_stop(state->timer); furi_timer_free(state->timer); state->timer = NULL; @@ -515,7 +515,7 @@ bail: } // 5. Free the mutex - if(state->mutex) { + if(state && state->mutex) { furi_mutex_free(state->mutex); state->mutex = NULL; } From 23c946ef50e07950199637776d2f520351ee7ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 3 May 2023 11:08:41 +0900 Subject: [PATCH 103/216] Move gauge calibration to separate header, add f18 calibration (#2622) --- firmware/targets/f18/api_symbols.csv | 1 + .../f18/furi_hal/furi_hal_power_calibration.h | 37 ++++++++++++++++++ firmware/targets/f7/api_symbols.csv | 1 + firmware/targets/f7/furi_hal/furi_hal_power.c | 38 +------------------ .../f7/furi_hal/furi_hal_power_calibration.h | 37 ++++++++++++++++++ 5 files changed, 77 insertions(+), 37 deletions(-) create mode 100644 firmware/targets/f18/furi_hal/furi_hal_power_calibration.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_power_calibration.h diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index eb2d6f43f..25f36ca02 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -36,6 +36,7 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, +Header,-,firmware/targets/f18/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,, diff --git a/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h b/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h new file mode 100644 index 000000000..e97e1657d --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_power_calibration.h @@ -0,0 +1,37 @@ +const ParamCEDV cedv = { + .cedv_conf.gauge_conf = + { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, + }, + .full_charge_cap = 1300, + .design_cap = 1300, + .EDV0 = 3300, + .EDV1 = 3321, + .EDV2 = 3355, + .EMF = 3679, + .C0 = 430, + .C1 = 0, + .R1 = 408, + .R0 = 334, + .T0 = 4626, + .TC = 11, + .DOD0 = 4044, + .DOD10 = 3905, + .DOD20 = 3807, + .DOD30 = 3718, + .DOD40 = 3642, + .DOD50 = 3585, + .DOD60 = 3546, + .DOD70 = 3514, + .DOD80 = 3477, + .DOD90 = 3411, + .DOD100 = 3299, +}; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d0c6b36ad..951e92aae 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -47,6 +47,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, +Header,-,firmware/targets/f7/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,, diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index e380de7fa..ec405f108 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -46,43 +46,7 @@ static volatile FuriHalPower furi_hal_power = { .suppress_charge = 0, }; -const ParamCEDV cedv = { - .cedv_conf.gauge_conf = - { - .CCT = 1, - .CSYNC = 0, - .EDV_CMP = 0, - .SC = 1, - .FIXED_EDV0 = 1, - .FCC_LIM = 1, - .FC_FOR_VDQ = 1, - .IGNORE_SD = 1, - .SME0 = 0, - }, - .full_charge_cap = 2101, - .design_cap = 2101, - .EDV0 = 3300, - .EDV1 = 3321, - .EDV2 = 3355, - .EMF = 3679, - .C0 = 430, - .C1 = 0, - .R1 = 408, - .R0 = 334, - .T0 = 4626, - .TC = 11, - .DOD0 = 4044, - .DOD10 = 3905, - .DOD20 = 3807, - .DOD30 = 3718, - .DOD40 = 3642, - .DOD50 = 3585, - .DOD60 = 3546, - .DOD70 = 3514, - .DOD80 = 3477, - .DOD90 = 3411, - .DOD100 = 3299, -}; +#include void furi_hal_power_init() { #ifdef FURI_HAL_POWER_DEBUG diff --git a/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h b/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h new file mode 100644 index 000000000..5eb0f938b --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h @@ -0,0 +1,37 @@ +const ParamCEDV cedv = { + .cedv_conf.gauge_conf = + { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, + }, + .full_charge_cap = 2101, + .design_cap = 2101, + .EDV0 = 3300, + .EDV1 = 3321, + .EDV2 = 3355, + .EMF = 3679, + .C0 = 430, + .C1 = 0, + .R1 = 408, + .R0 = 334, + .T0 = 4626, + .TC = 11, + .DOD0 = 4044, + .DOD10 = 3905, + .DOD20 = 3807, + .DOD30 = 3718, + .DOD40 = 3642, + .DOD50 = 3585, + .DOD60 = 3546, + .DOD70 = 3514, + .DOD80 = 3477, + .DOD90 = 3411, + .DOD100 = 3299, +}; From 8b8f65c5ae0de6c100a2567264130e855b2c5561 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 03:11:26 +0100 Subject: [PATCH 104/216] BadKB fix BT_ID command --- applications/main/bad_kb/helpers/ducky_script_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/bad_kb/helpers/ducky_script_commands.c b/applications/main/bad_kb/helpers/ducky_script_commands.c index f23ab2f8a..42ed1b9e8 100644 --- a/applications/main/bad_kb/helpers/ducky_script_commands.c +++ b/applications/main/bad_kb/helpers/ducky_script_commands.c @@ -171,6 +171,7 @@ static int32_t ducky_fnc_waitforbutton(BadKbScript* bad_kb, const char* line, in static const DuckyCmd ducky_commands[] = { {"REM", NULL, -1}, {"ID", NULL, -1}, + {"BT_ID", NULL, -1}, {"DELAY", ducky_fnc_delay, -1}, {"STRING", ducky_fnc_string, 0}, {"STRINGLN", ducky_fnc_string, 1}, From 5c09bc5b2d25da5fa6fc71e82eb316ed9db87c1f Mon Sep 17 00:00:00 2001 From: Lewis Westbury Date: Wed, 3 May 2023 04:33:30 +0100 Subject: [PATCH 105/216] Gui: relax some asserts in view (#2623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove assertion preventing replacement of view input callback * Gui: relax some asserts in view Co-authored-by: あく --- applications/services/gui/view.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/applications/services/gui/view.c b/applications/services/gui/view.c index 4d84cac50..07ae072a1 100644 --- a/applications/services/gui/view.c +++ b/applications/services/gui/view.c @@ -19,19 +19,16 @@ void view_tie_icon_animation(View* view, IconAnimation* icon_animation) { void view_set_draw_callback(View* view, ViewDrawCallback callback) { furi_assert(view); - furi_assert(view->draw_callback == NULL); view->draw_callback = callback; } void view_set_input_callback(View* view, ViewInputCallback callback) { furi_assert(view); - furi_assert(view->input_callback == NULL); view->input_callback = callback; } void view_set_custom_callback(View* view, ViewCustomCallback callback) { furi_assert(view); - furi_assert(callback); view->custom_callback = callback; } @@ -62,7 +59,6 @@ void view_set_update_callback_context(View* view, void* context) { void view_set_context(View* view, void* context) { furi_assert(view); - furi_assert(context); view->context = context; } From c5b460b416e24fa887ec93672e56b71109c91a79 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 3 May 2023 06:58:59 +0300 Subject: [PATCH 106/216] [FL-3260] Added API version to device info (#2611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * hal: device_info: added API version to "firmware.api.major" & "firmware.api.minor" * FuriHal: bump device info version Co-authored-by: あく --- .../loader/firmware_api/firmware_api.cpp | 7 +++++++ firmware/targets/f18/api_symbols.csv | 3 ++- firmware/targets/f7/api_symbols.csv | 3 ++- firmware/targets/f7/furi_hal/furi_hal_info.c | 16 ++++++++++++++-- .../targets/furi_hal_include/furi_hal_info.h | 2 ++ furi/core/common_defines.h | 4 ++++ 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/applications/services/loader/firmware_api/firmware_api.cpp b/applications/services/loader/firmware_api/firmware_api.cpp index 52e86efc2..6651bf112 100644 --- a/applications/services/loader/firmware_api/firmware_api.cpp +++ b/applications/services/loader/firmware_api/firmware_api.cpp @@ -6,6 +6,8 @@ /* Generated table */ #include +#include + static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!"); constexpr HashtableApiInterface elf_api_interface{ @@ -19,3 +21,8 @@ constexpr HashtableApiInterface elf_api_interface{ }; const ElfApiInterface* const firmware_api_interface = &elf_api_interface; + +extern "C" void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) { + *major = elf_api_interface.api_version_major; + *minor = elf_api_interface.api_version_minor; +} \ No newline at end of file diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 25f36ca02..bdd5d6b61 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,+,23.0,, +Version,+,23.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -960,6 +960,7 @@ Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_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_info_get,void,"PropertyValueCallback, char, void*" +Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*" Function,-,furi_hal_init,void, Function,-,furi_hal_init_early,void, Function,-,furi_hal_interrupt_init,void, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 951e92aae..9f4ec4261 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,23.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1148,6 +1148,7 @@ 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_info_get_api_version,void,"uint16_t*, uint16_t*" Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*" Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t Function,+,furi_hal_infrared_async_rx_set_timeout_isr_callback,void,"FuriHalInfraredRxTimeoutCallback, void*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index c984ef4d5..4c034ff35 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -8,6 +8,11 @@ #include #include +FURI_WEAK void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) { + *major = 0; + *minor = 0; +} + void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { FuriString* key = furi_string_alloc(); FuriString* value = furi_string_alloc(); @@ -18,10 +23,10 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { // Device Info version if(sep == '.') { property_value_out(&property_context, NULL, 2, "format", "major", "3"); - property_value_out(&property_context, NULL, 2, "format", "minor", "0"); + property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); - property_value_out(&property_context, NULL, 3, "device", "info", "minor", "0"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); } // Model name @@ -161,6 +166,13 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { version_get_builddate(firmware_version)); property_value_out( &property_context, "%d", 2, "firmware", "target", version_get_target(firmware_version)); + + uint16_t api_version_major, api_version_minor; + furi_hal_info_get_api_version(&api_version_major, &api_version_minor); + property_value_out( + &property_context, "%d", 3, "firmware", "api", "major", api_version_major); + property_value_out( + &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); } if(furi_hal_bt_is_alive()) { diff --git a/firmware/targets/furi_hal_include/furi_hal_info.h b/firmware/targets/furi_hal_include/furi_hal_info.h index fa3267f5d..7e8b0e1fb 100644 --- a/firmware/targets/furi_hal_include/furi_hal_info.h +++ b/firmware/targets/furi_hal_include/furi_hal_info.h @@ -14,6 +14,8 @@ extern "C" { #endif +void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor); + /** Get device information * * @param[in] callback callback to provide with new data diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index 1ec847d45..d7bfaf207 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -15,6 +15,10 @@ extern "C" { #define FURI_WARN_UNUSED __attribute__((warn_unused_result)) #endif +#ifndef FURI_WEAK +#define FURI_WEAK __attribute__((weak)) +#endif + #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif From dfbacd1a4753d64d76b1ac85da8f5bc9a46ecbd5 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Tue, 2 May 2023 21:05:24 -0700 Subject: [PATCH 107/216] [#2612] Remove spaces in CSN(#2616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../external/picopass/scenes/picopass_scene_read_card_success.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/picopass/scenes/picopass_scene_read_card_success.c b/applications/external/picopass/scenes/picopass_scene_read_card_success.c index 198b21d98..cc18ac066 100644 --- a/applications/external/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/external/picopass/scenes/picopass_scene_read_card_success.c @@ -34,7 +34,7 @@ void picopass_scene_read_card_success_on_enter(void* context) { 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]); } bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN); From 59386f9fa9e8b3f9b03823c99405484dddaec071 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 3 May 2023 08:15:47 +0400 Subject: [PATCH 108/216] WS: add protocol "Wendox W6726" (#2604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WS: add protocol "Wendox" * WS: add bat status * WS: add CRC, refactoring * WS: description added * WS: fix name file * WeatherStation: cleanup alien symbols Co-authored-by: あく --- .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + .../weather_station/protocols/wendox_w6726.c | 299 ++++++++++++++++++ .../weather_station/protocols/wendox_w6726.h | 80 +++++ 4 files changed, 381 insertions(+) create mode 100644 applications/external/weather_station/protocols/wendox_w6726.c create mode 100644 applications/external/weather_station/protocols/wendox_w6726.h diff --git a/applications/external/weather_station/protocols/protocol_items.c b/applications/external/weather_station/protocols/protocol_items.c index 2c9d751c7..cd4bae76d 100644 --- a/applications/external/weather_station/protocols/protocol_items.c +++ b/applications/external/weather_station/protocols/protocol_items.c @@ -16,6 +16,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_auriol_th, &ws_protocol_oregon_v1, &ws_protocol_tx_8300, + &ws_protocol_wendox_w6726, }; const SubGhzProtocolRegistry weather_station_protocol_registry = { diff --git a/applications/external/weather_station/protocols/protocol_items.h b/applications/external/weather_station/protocols/protocol_items.h index f9e443abc..0398c11f2 100644 --- a/applications/external/weather_station/protocols/protocol_items.h +++ b/applications/external/weather_station/protocols/protocol_items.h @@ -16,5 +16,6 @@ #include "auriol_hg0601a.h" #include "oregon_v1.h" #include "tx_8300.h" +#include "wendox_w6726.h" extern const SubGhzProtocolRegistry weather_station_protocol_registry; diff --git a/applications/external/weather_station/protocols/wendox_w6726.c b/applications/external/weather_station/protocols/wendox_w6726.c new file mode 100644 index 000000000..2fbe961f7 --- /dev/null +++ b/applications/external/weather_station/protocols/wendox_w6726.c @@ -0,0 +1,299 @@ +#include "wendox_w6726.h" + +#define TAG "WSProtocolWendoxW6726" + +/* + * Wendox W6726 + * + * Temperature -50C to +70C + * _ _ _ __ _ + * _| |___| |___| |___ ... | |_| |__...._______________ + * preamble data guard time + * + * 3 reps every 3 minutes + * in the first message 11 bytes of the preamble in the rest by 7 + * + * bit 0: 1955-hi, 5865-lo + * bit 1: 5865-hi, 1955-lo + * guard time: 12*1955+(lo last bit) + * data: 29 bit + * + * IIIII | ZTTTTTTTTT | uuuuuuuBuu | CCCC + * + * I: identification; + * Z: temperature sign; + * T: temperature sign dependent +12C; + * B: battery low; flag to indicate low battery voltage; + * C: CRC4 (polynomial = 0x9, start_data = 0xD); + * u: unknown; + */ + +static const SubGhzBlockConst ws_protocol_wendox_w6726_const = { + .te_short = 1955, + .te_long = 5865, + .te_delta = 300, + .min_count_bit_for_found = 29, +}; + +struct WSProtocolDecoderWendoxW6726 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + + uint16_t header_count; +}; + +struct WSProtocolEncoderWendoxW6726 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + WendoxW6726DecoderStepReset = 0, + WendoxW6726DecoderStepCheckPreambule, + WendoxW6726DecoderStepSaveDuration, + WendoxW6726DecoderStepCheckDuration, +} WendoxW6726DecoderStep; + +const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder = { + .alloc = ws_protocol_decoder_wendox_w6726_alloc, + .free = ws_protocol_decoder_wendox_w6726_free, + + .feed = ws_protocol_decoder_wendox_w6726_feed, + .reset = ws_protocol_decoder_wendox_w6726_reset, + + .get_hash_data = ws_protocol_decoder_wendox_w6726_get_hash_data, + .serialize = ws_protocol_decoder_wendox_w6726_serialize, + .deserialize = ws_protocol_decoder_wendox_w6726_deserialize, + .get_string = ws_protocol_decoder_wendox_w6726_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_wendox_w6726 = { + .name = WS_PROTOCOL_WENDOX_W6726_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_wendox_w6726_decoder, + .encoder = &ws_protocol_wendox_w6726_encoder, +}; + +void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderWendoxW6726* instance = malloc(sizeof(WSProtocolDecoderWendoxW6726)); + instance->base.protocol = &ws_protocol_wendox_w6726; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_wendox_w6726_free(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + free(instance); +} + +void ws_protocol_decoder_wendox_w6726_reset(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + instance->decoder.parser_step = WendoxW6726DecoderStepReset; +} + +static bool ws_protocol_wendox_w6726_check(WSProtocolDecoderWendoxW6726* instance) { + if(!instance->decoder.decode_data) return false; + uint8_t msg[] = { + instance->decoder.decode_data >> 28, + instance->decoder.decode_data >> 20, + instance->decoder.decode_data >> 12, + instance->decoder.decode_data >> 4}; + + uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD); + return (crc == (instance->decoder.decode_data & 0x0F)); +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_wendox_w6726_remote_controller(WSBlockGeneric* instance) { + instance->id = (instance->data >> 24) & 0xFF; + instance->battery_low = (instance->data >> 6) & 1; + instance->channel = WS_NO_CHANNEL; + + if(((instance->data >> 23) & 1)) { + instance->temp = (float)(((instance->data >> 14) & 0x1FF) + 12) / 10.0f; + } else { + instance->temp = (float)((~(instance->data >> 14) & 0x1FF) + 1 - 12) / -10.0f; + } + + if(instance->temp < -50.0f) { + instance->temp = -50.0f; + } else if(instance->temp > 70.0f) { + instance->temp = 70.0f; + } + + instance->btn = WS_NO_BTN; + instance->humidity = WS_NO_HUMIDITY; +} + +void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + + switch(instance->decoder.parser_step) { + case WendoxW6726DecoderStepReset: + if((level) && (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + instance->decoder.parser_step = WendoxW6726DecoderStepCheckPreambule; + instance->decoder.te_last = duration; + instance->header_count = 0; + } + break; + + case WendoxW6726DecoderStepCheckPreambule: + if(level) { + instance->decoder.te_last = duration; + } else { + if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta * 1) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2)) { + instance->header_count++; + } else if((instance->header_count > 4) && (instance->header_count < 12)) { + if((DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + } + break; + + case WendoxW6726DecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = WendoxW6726DecoderStepCheckDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + break; + + case WendoxW6726DecoderStepCheckDuration: + if(!level) { + if(duration > + ws_protocol_wendox_w6726_const.te_short + ws_protocol_wendox_w6726_const.te_long) { + if(DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else if( + DURATION_DIFF( + instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + if((instance->decoder.decode_count_bit == + ws_protocol_wendox_w6726_const.min_count_bit_for_found) && + ws_protocol_wendox_w6726_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_wendox_w6726_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_wendox_w6726_const.te_long) < + ws_protocol_wendox_w6726_const.te_delta * 2) && + (DURATION_DIFF(duration, ws_protocol_wendox_w6726_const.te_short) < + ws_protocol_wendox_w6726_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = WendoxW6726DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + } else { + instance->decoder.parser_step = WendoxW6726DecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + return ws_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + ws_protocol_wendox_w6726_const.min_count_bit_for_found); +} + +void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderWendoxW6726* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/external/weather_station/protocols/wendox_w6726.h b/applications/external/weather_station/protocols/wendox_w6726.h new file mode 100644 index 000000000..236777a1c --- /dev/null +++ b/applications/external/weather_station/protocols/wendox_w6726.h @@ -0,0 +1,80 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_WENDOX_W6726_NAME "Wendox W6726" + +typedef struct WSProtocolDecoderWendoxW6726 WSProtocolDecoderWendoxW6726; +typedef struct WSProtocolEncoderWendoxW6726 WSProtocolEncoderWendoxW6726; + +extern const SubGhzProtocolDecoder ws_protocol_wendox_w6726_decoder; +extern const SubGhzProtocolEncoder ws_protocol_wendox_w6726_encoder; +extern const SubGhzProtocol ws_protocol_wendox_w6726; + +/** + * Allocate WSProtocolDecoderWendoxW6726. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderWendoxW6726* pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void* ws_protocol_decoder_wendox_w6726_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void ws_protocol_decoder_wendox_w6726_free(void* context); + +/** + * Reset decoder WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + */ +void ws_protocol_decoder_wendox_w6726_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_wendox_w6726_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_wendox_w6726_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus ws_protocol_decoder_wendox_w6726_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderWendoxW6726. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + ws_protocol_decoder_wendox_w6726_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderWendoxW6726 instance + * @param output Resulting text + */ +void ws_protocol_decoder_wendox_w6726_get_string(void* context, FuriString* output); From 015ab4a0242c9c9c7ff182afd42b81cbecee758c Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 3 May 2023 07:39:14 +0300 Subject: [PATCH 109/216] [#2591] BadUSB: command parser fix (#2607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../bad_usb/helpers/ducky_script_commands.c | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/applications/main/bad_usb/helpers/ducky_script_commands.c b/applications/main/bad_usb/helpers/ducky_script_commands.c index 1498c9a73..d073b4c8d 100644 --- a/applications/main/bad_usb/helpers/ducky_script_commands.c +++ b/applications/main/bad_usb/helpers/ducky_script_commands.c @@ -152,22 +152,22 @@ static int32_t ducky_fnc_waitforbutton(BadUsbScript* bad_usb, const char* line, } static const DuckyCmd ducky_commands[] = { - {"REM ", NULL, -1}, - {"ID ", NULL, -1}, - {"DELAY ", ducky_fnc_delay, -1}, - {"STRING ", ducky_fnc_string, 0}, - {"STRINGLN ", ducky_fnc_string, 1}, - {"DEFAULT_DELAY ", ducky_fnc_defdelay, -1}, - {"DEFAULTDELAY ", ducky_fnc_defdelay, -1}, - {"STRINGDELAY ", ducky_fnc_strdelay, -1}, - {"STRING_DELAY ", ducky_fnc_strdelay, -1}, - {"REPEAT ", ducky_fnc_repeat, -1}, - {"SYSRQ ", ducky_fnc_sysrq, -1}, - {"ALTCHAR ", ducky_fnc_altchar, -1}, - {"ALTSTRING ", ducky_fnc_altstring, -1}, - {"ALTCODE ", ducky_fnc_altstring, -1}, - {"HOLD ", ducky_fnc_hold, -1}, - {"RELEASE ", ducky_fnc_release, -1}, + {"REM", NULL, -1}, + {"ID", NULL, -1}, + {"DELAY", ducky_fnc_delay, -1}, + {"STRING", ducky_fnc_string, 0}, + {"STRINGLN", ducky_fnc_string, 1}, + {"DEFAULT_DELAY", ducky_fnc_defdelay, -1}, + {"DEFAULTDELAY", ducky_fnc_defdelay, -1}, + {"STRINGDELAY", ducky_fnc_strdelay, -1}, + {"STRING_DELAY", ducky_fnc_strdelay, -1}, + {"REPEAT", ducky_fnc_repeat, -1}, + {"SYSRQ", ducky_fnc_sysrq, -1}, + {"ALTCHAR", ducky_fnc_altchar, -1}, + {"ALTSTRING", ducky_fnc_altstring, -1}, + {"ALTCODE", ducky_fnc_altstring, -1}, + {"HOLD", ducky_fnc_hold, -1}, + {"RELEASE", ducky_fnc_release, -1}, {"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1}, }; @@ -175,8 +175,15 @@ static const DuckyCmd ducky_commands[] = { #define WORKER_TAG TAG "Worker" int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) { + size_t cmd_word_len = strcspn(line, " "); for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) { - if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) { + size_t cmd_compare_len = strlen(ducky_commands[i].name); + + if(cmd_compare_len != cmd_word_len) { + continue; + } + + if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) { if(ducky_commands[i].callback == NULL) { return 0; } else { From c3ececcf969576f2099fd45be80d5e4f213dc9b5 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 3 May 2023 08:48:49 +0300 Subject: [PATCH 110/216] [FL-3174] Dolphin builder in ufbt; minor ufbt/fbt improvements (#2601) * ufbt: added "dolphin_ext" target (expects "external" subfolder in cwd with dolphin assets); cleaned up unused code * ufbt: codestyle fixes * scripts: fixed style according to ruff linter * scripts: additional cleanup & codestyle fixes * github: pass target hw code when installing local SDK with ufbt * ufbt: added error message for missing folder in dolphin builder * scripts: more linter fixes * sdk: added flipper_format_stream; ufbt: support for --extra-define * fbt: reduced amount of global defines * scripts, fbt: rearranged imports Co-authored-by: Aleksandr Kutuzov --- .github/workflows/build.yml | 2 + assets/SConscript | 4 +- firmware.scons | 4 +- firmware/targets/f18/api_symbols.csv | 8 +++- firmware/targets/f7/api_symbols.csv | 8 +++- lib/flipper_format/SConscript | 1 + lib/freertos.scons | 3 -- lib/libusb_stm32.scons | 8 ++-- lib/littlefs.scons | 8 ++-- lib/misc.scons | 4 +- lib/toolbox/SConscript | 4 +- scripts/assets.py | 32 ++++++------- scripts/distfap.py | 6 +-- scripts/fbt/appmanifest.py | 12 ++--- scripts/fbt/elfmanifest.py | 4 +- scripts/fbt/fapassets.py | 2 +- scripts/fbt/sdk/cache.py | 17 +++---- scripts/fbt/util.py | 9 ++-- scripts/fbt/version.py | 2 +- scripts/fbt_tools/ccache.py | 2 +- scripts/fbt_tools/crosscc.py | 14 +++--- scripts/fbt_tools/fbt_apps.py | 13 +++--- scripts/fbt_tools/fbt_assets.py | 14 +++--- scripts/fbt_tools/fbt_debugopts.py | 2 - scripts/fbt_tools/fbt_dist.py | 3 +- scripts/fbt_tools/fbt_extapps.py | 18 +++----- scripts/fbt_tools/fbt_hwtarget.py | 2 - scripts/fbt_tools/fbt_sdk.py | 19 ++++---- scripts/fbt_tools/fbt_tweaks.py | 12 +++-- scripts/fbt_tools/fbt_version.py | 2 +- scripts/fbt_tools/fwbin.py | 4 +- scripts/fbt_tools/gdb.py | 4 -- scripts/fbt_tools/objdump.py | 2 +- scripts/fbt_tools/openocd.py | 6 +-- scripts/fbt_tools/pvsstudio.py | 13 +++--- scripts/fbt_tools/sconsmodular.py | 3 +- scripts/fbt_tools/sconsrecursiveglob.py | 2 +- scripts/fbt_tools/strip.py | 2 +- scripts/flash.py | 50 ++++++++++----------- scripts/flipper/app.py | 2 +- scripts/flipper/assets/copro.py | 8 ++-- scripts/flipper/assets/coprobin.py | 3 +- scripts/flipper/assets/dolphin.py | 12 +++-- scripts/flipper/assets/icon.py | 12 ++--- scripts/flipper/assets/manifest.py | 5 +-- scripts/flipper/assets/obdata.py | 4 +- scripts/flipper/cube.py | 8 ++-- scripts/flipper/storage.py | 4 +- scripts/flipper/utils/__init__.py | 1 - scripts/flipper/utils/programmer_openocd.py | 10 ++--- scripts/flipper/utils/stm32wb55.py | 6 +-- scripts/flipper/utils/templite.py | 4 +- scripts/fwsize.py | 7 +-- scripts/get_env.py | 14 +++--- scripts/lint.py | 11 +++-- scripts/merge_report_qa.py | 3 +- scripts/meta.py | 3 +- scripts/ob.py | 4 +- scripts/otp.py | 37 +++++++-------- scripts/program.py | 14 +++--- scripts/runfap.py | 12 +++-- scripts/sconsdist.py | 2 +- scripts/selfupdate.py | 12 +++-- scripts/serial_cli.py | 5 ++- scripts/storage.py | 12 ++--- scripts/ufbt/SConstruct | 37 ++++++++++----- scripts/ufbt/commandline.scons | 34 +++++--------- scripts/ufbt/site_init.py | 6 +-- scripts/ufbt/site_tools/ufbt_state.py | 7 ++- scripts/ufbt/update.scons | 37 --------------- scripts/update.py | 20 ++++----- scripts/version.py | 8 ++-- site_scons/extapps.scons | 4 +- 73 files changed, 311 insertions(+), 382 deletions(-) delete mode 100644 scripts/ufbt/update.scons diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0934eec76..d69318530 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -193,12 +193,14 @@ jobs: TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \ ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT + echo "hw-target-code=$TARGET" >> $GITHUB_OUTPUT - name: Deploy uFBT with SDK uses: flipperdevices/flipperzero-ufbt-action@v0.1.0 with: task: setup sdk-file: ${{ steps.build-fw.outputs.sdk-file }} + sdk-hw-target: ${{ steps.build-fw.outputs.hw-target-code }} - name: Build test app with SDK run: | diff --git a/assets/SConscript b/assets/SConscript index 21437aa30..9bd273626 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,7 +1,7 @@ -Import("env") - from fbt.version import get_git_commit_unix_timestamp +Import("env") + assetsenv = env.Clone( tools=["fbt_assets"], FW_LIB_NAME="assets", diff --git a/firmware.scons b/firmware.scons index c7fdc6392..c46996899 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,5 +1,3 @@ -Import("ENV", "fw_build_meta") - from SCons.Errors import UserError from SCons.Node import FS @@ -10,6 +8,8 @@ from fbt_extra.util import ( link_elf_dir_as_latest, ) +Import("ENV", "fw_build_meta") + # Building initial C environment for libs env = ENV.Clone( tools=[ diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bdd5d6b61..f84bf074e 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,+,23.1,, +Version,+,23.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -112,6 +112,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/flipper_format/flipper_format_stream.h,, Header,+,lib/libusb_stm32/inc/hid_usage_button.h,, Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,, Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,, @@ -755,6 +756,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32 Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool" +Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool" +Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool" +Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*" +Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*" Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9f4ec4261..c176b2d7e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.1,, +Version,+,23.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -118,6 +118,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/flipper_format/flipper_format_stream.h,, Header,+,lib/ibutton/ibutton_key.h,, Header,+,lib/ibutton/ibutton_protocols.h,, Header,+,lib/ibutton/ibutton_worker.h,, @@ -918,6 +919,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32 Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool" +Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool" +Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool" +Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*" +Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*" Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 353da8035..9c9e8b6f3 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -7,6 +7,7 @@ env.Append( SDK_HEADERS=[ File("flipper_format.h"), File("flipper_format_i.h"), + File("flipper_format_stream.h"), ], ) diff --git a/lib/freertos.scons b/lib/freertos.scons index 1c5a5bf54..cb0006e56 100644 --- a/lib/freertos.scons +++ b/lib/freertos.scons @@ -7,9 +7,6 @@ env.Append( "#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F", "#/lib/FreeRTOS-glue", ], - CPPDEFINES=[ - "HAVE_FREERTOS", - ], ) diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons index 4838b7c50..ccc5de24f 100644 --- a/lib/libusb_stm32.scons +++ b/lib/libusb_stm32.scons @@ -4,9 +4,6 @@ env.Append( CPPPATH=[ "#/lib/libusb_stm32/inc", ], - CPPDEFINES=[ - ("USB_PMASIZE", "0x400"), - ], SDK_HEADERS=env.GlobRecursive( "*.h", Dir("libusb_stm32/inc"), @@ -16,6 +13,11 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="usb_stm32") libenv.ApplyLibFlags() +libenv.Append( + CPPDEFINES=[ + ("USB_PMASIZE", "0x400"), + ], +) sources = [ diff --git a/lib/littlefs.scons b/lib/littlefs.scons index 792142c32..3d68e07ba 100644 --- a/lib/littlefs.scons +++ b/lib/littlefs.scons @@ -4,14 +4,16 @@ env.Append( CPPPATH=[ "#/lib/littlefs", ], - CPPDEFINES=[ - ("LFS_CONFIG", "lfs_config.h"), - ], ) libenv = env.Clone(FW_LIB_NAME="littlefs") libenv.ApplyLibFlags() +libenv.Append( + CPPDEFINES=[ + ("LFS_CONFIG", "lfs_config.h"), + ], +) sources = Glob("littlefs/*.c", source=True) diff --git a/lib/misc.scons b/lib/misc.scons index b479851b1..1ff6e2fb0 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -1,7 +1,7 @@ -Import("env") - from fbt.util import GLOB_FILE_EXCLUSION +Import("env") + env.Append( CPPPATH=[ "#/lib/digital_signal", diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index bb06c2db4..4e158e30e 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,8 +1,8 @@ -Import("env") - from fbt.version import get_fast_git_version_id +Import("env") + env.Append( CPPPATH=[ "#/lib/toolbox", diff --git a/scripts/assets.py b/scripts/assets.py index 75bebcfb4..c0fa9100b 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 +import os + from flipper.app import App from flipper.assets.icon import file2image -import os - ICONS_SUPPORTED_FORMATS = ["png"] ICONS_TEMPLATE_H_HEADER = """#pragma once @@ -127,7 +127,7 @@ class Main(App): if not filenames: continue if "frame_rate" in filenames: - self.logger.debug(f"Folder contains animation") + self.logger.debug("Folder contains animation") icon_name = "A_" + os.path.split(dirpath)[1].replace("-", "_") width = height = None frame_count = 0 @@ -186,7 +186,7 @@ class Main(App): icons_c.write("\n") icons.append((icon_name, width, height, 0, 1)) # Create array of images: - self.logger.debug(f"Finalizing source file") + self.logger.debug("Finalizing source file") for name, width, height, frame_rate, frame_count in icons: icons_c.write( ICONS_TEMPLATE_C_ICONS.format( @@ -201,7 +201,7 @@ class Main(App): icons_c.close() # Create Public Header - self.logger.debug(f"Creating header") + self.logger.debug("Creating header") icons_h = open( os.path.join(self.args.output_directory, f"{self.args.filename}.h"), "w", @@ -211,7 +211,7 @@ class Main(App): for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) icons_h.close() - self.logger.debug(f"Done") + self.logger.debug("Done") return 0 def manifest(self): @@ -232,7 +232,7 @@ class Main(App): new_manifest = Manifest(self.args.timestamp) new_manifest.create(directory_path) - self.logger.info(f"Comparing new manifest with existing") + self.logger.info("Comparing new manifest with existing") only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) for record in only_in_old: self.logger.info(f"Only in old: {record}") @@ -246,38 +246,38 @@ class Main(App): else: self.logger.info("Manifest is up-to-date!") - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def copro(self): from flipper.assets.copro import Copro - self.logger.info(f"Bundling coprocessor binaries") + self.logger.info("Bundling coprocessor binaries") copro = Copro(self.args.mcu) - self.logger.info(f"Loading CUBE info") + self.logger.info("Loading CUBE info") copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver) - self.logger.info(f"Bundling") + self.logger.info("Bundling") copro.bundle( self.args.output_dir, self.args.stack_file, self.args.stack_type, self.args.stack_addr, ) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def dolphin(self): from flipper.assets.dolphin import Dolphin - self.logger.info(f"Processing Dolphin sources") + self.logger.info("Processing Dolphin sources") dolphin = Dolphin() - self.logger.info(f"Loading data") + self.logger.info("Loading data") dolphin.load(self.args.input_directory) - self.logger.info(f"Packing") + self.logger.info("Packing") dolphin.pack(self.args.output_directory, self.args.symbol_name) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 diff --git a/scripts/distfap.py b/scripts/distfap.py index 060fe26ff..d330988b5 100644 --- a/scripts/distfap.py +++ b/scripts/distfap.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 +import os +import posixpath + from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.utils.cdc import resolve_port -import os -import posixpath - class Main(App): def init(self): diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 37ddc4348..5e41f4c0e 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -1,7 +1,7 @@ -from dataclasses import dataclass, field -from typing import List, Optional, Tuple, Callable -from enum import Enum import os +from dataclasses import dataclass, field +from enum import Enum +from typing import Callable, List, Optional, Tuple class FlipperManifestException(Exception): @@ -93,7 +93,7 @@ class AppManager: def get(self, appname: str): try: return self.known_apps[appname] - except KeyError as _: + except KeyError: raise FlipperManifestException( f"Missing application manifest for '{appname}'" ) @@ -223,6 +223,7 @@ class AppBuildset: return self.appmgr.get(app_name).supports_hardware_target(self.hw_target) def _get_app_depends(self, app_name: str) -> List[str]: + app_def = self.appmgr.get(app_name) # Skip app if its target is not supported by the target we are building for if not self._check_if_app_target_supported(app_name): self._writer( @@ -230,7 +231,6 @@ class AppBuildset: ) return [] - app_def = self.appmgr.get(app_name) return list( filter( self._check_if_app_target_supported, @@ -296,7 +296,7 @@ class AppBuildset: try: parent_app = self.appmgr.get(parent_app_id) parent_app._plugins.append(extension_app) - except FlipperManifestException as e: + except FlipperManifestException: self._writer( f"Module {extension_app.appid} has unknown parent {parent_app_id}" ) diff --git a/scripts/fbt/elfmanifest.py b/scripts/fbt/elfmanifest.py index 17bceddf4..333888e14 100644 --- a/scripts/fbt/elfmanifest.py +++ b/scripts/fbt/elfmanifest.py @@ -1,12 +1,10 @@ -from dataclasses import dataclass import os - import struct from dataclasses import dataclass, field -from .appmanifest import FlipperApplication from flipper.assets.icon import file2image +from .appmanifest import FlipperApplication _MANIFEST_MAGIC = 0x52474448 diff --git a/scripts/fbt/fapassets.py b/scripts/fbt/fapassets.py index 0649f03ef..9902fd79a 100644 --- a/scripts/fbt/fapassets.py +++ b/scripts/fbt/fapassets.py @@ -1,5 +1,5 @@ -import os import hashlib +import os import struct from typing import TypedDict diff --git a/scripts/fbt/sdk/cache.py b/scripts/fbt/sdk/cache.py index 756c37827..b6f6edbe5 100644 --- a/scripts/fbt/sdk/cache.py +++ b/scripts/fbt/sdk/cache.py @@ -1,20 +1,13 @@ -import operator -import os import csv import operator - -from enum import Enum, auto -from typing import Set, ClassVar, Any +import os from dataclasses import dataclass +from enum import Enum, auto +from typing import Any, ClassVar, Set from ansi.color import fg -from . import ( - ApiEntries, - ApiEntryFunction, - ApiEntryVariable, - ApiHeader, -) +from . import ApiEntries, ApiEntryFunction, ApiEntryVariable, ApiHeader @dataclass(frozen=True) @@ -137,7 +130,7 @@ class SdkCache: f"API version is still WIP: {self.version}. Review the changes and re-run command." ) ) - print(f"CSV file entries to mark up:") + print("CSV file entries to mark up:") print( fg.yellow( "\n".join( diff --git a/scripts/fbt/util.py b/scripts/fbt/util.py index 7bdaea031..ae850a8c3 100644 --- a/scripts/fbt/util.py +++ b/scripts/fbt/util.py @@ -1,10 +1,9 @@ -import SCons -from SCons.Subst import quote_spaces -from SCons.Errors import StopError - -import re import os +import re +import SCons +from SCons.Errors import StopError +from SCons.Subst import quote_spaces WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") diff --git a/scripts/fbt/version.py b/scripts/fbt/version.py index e7fe2edaf..09f48c8eb 100644 --- a/scripts/fbt/version.py +++ b/scripts/fbt/version.py @@ -1,5 +1,5 @@ -import subprocess import datetime +import subprocess from functools import cache diff --git a/scripts/fbt_tools/ccache.py b/scripts/fbt_tools/ccache.py index e88886ade..63577ab78 100644 --- a/scripts/fbt_tools/ccache.py +++ b/scripts/fbt_tools/ccache.py @@ -3,7 +3,7 @@ def exists(): def generate(env): - if ccache := env.WhereIs("ccache"): + if env.WhereIs("ccache"): env["CCACHE"] = "ccache" env["CC_NOCACHE"] = env["CC"] env["CC"] = "$CCACHE $CC_NOCACHE" diff --git a/scripts/fbt_tools/crosscc.py b/scripts/fbt_tools/crosscc.py index dd5cd5319..d0631ca33 100644 --- a/scripts/fbt_tools/crosscc.py +++ b/scripts/fbt_tools/crosscc.py @@ -1,15 +1,11 @@ -from SCons.Errors import StopError -from SCons.Tool import asm -from SCons.Tool import gcc -from SCons.Tool import gxx -from SCons.Tool import ar -from SCons.Tool import gnulink -import strip +import subprocess + import gdb import objdump - +import strip from SCons.Action import _subproc -import subprocess +from SCons.Errors import StopError +from SCons.Tool import ar, asm, gcc, gnulink, gxx def prefix_commands(env, command_prefix, cmd_list): diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 9dbe30720..053a69503 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,15 +1,14 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Errors import StopError -from SCons.Warnings import warn, WarningOnByDefault from ansi.color import fg - from fbt.appmanifest import ( - FlipperAppType, - AppManager, ApplicationsCGenerator, + AppManager, + FlipperAppType, FlipperManifestException, ) +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import StopError +from SCons.Warnings import WarningOnByDefault, warn # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index e4c567993..68617c254 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -1,10 +1,10 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Errors import StopError - import os import subprocess + from ansi.color import fg +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import StopError def icons_emitter(target, source, env): @@ -76,11 +76,11 @@ def proto_ver_generator(target, source, env): target_file = target[0] src_dir = source[0].dir.abspath try: - git_fetch = _invoke_git( + _invoke_git( ["fetch", "--tags"], source_dir=src_dir, ) - except (subprocess.CalledProcessError, EnvironmentError) as e: + except (subprocess.CalledProcessError, EnvironmentError): # Not great, not terrible print(fg.boldred("Git: fetch failed")) @@ -89,7 +89,7 @@ def proto_ver_generator(target, source, env): ["describe", "--tags", "--abbrev=0"], source_dir=src_dir, ) - except (subprocess.CalledProcessError, EnvironmentError) as e: + except (subprocess.CalledProcessError, EnvironmentError): raise StopError("Git: describe failed") git_major, git_minor = git_describe.split(".") diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index 9abe59893..33cc0c076 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -1,5 +1,3 @@ -from re import search - from SCons.Errors import UserError diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index d2808419c..a43d62e9d 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -1,6 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action -from SCons.Script import Mkdir +from SCons.Builder import Builder from SCons.Defaults import Touch diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 4ac1c6873..1a1bad29e 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -3,23 +3,19 @@ import os import pathlib import shutil from dataclasses import dataclass, field -from typing import Optional, TypedDict - -from ansi.color import fg +from typing import Optional import SCons.Warnings -from SCons.Action import Action -from SCons.Builder import Builder -from SCons.Errors import UserError -from SCons.Node import NodeList -from SCons.Node.FS import File, Entry - +from ansi.color import fg from fbt.appmanifest import FlipperApplication, FlipperAppType, FlipperManifestException from fbt.elfmanifest import assemble_manifest_data from fbt.fapassets import FileBundler from fbt.sdk.cache import SdkCache from fbt.util import extract_abs_dir_path - +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import UserError +from SCons.Node.FS import Entry, File _FAP_META_SECTION = ".fapmeta" _FAP_FILEASSETS_SECTION = ".fapassets" @@ -289,7 +285,7 @@ def GetExtAppByIdOrPath(env, app_dir): try: # Maybe user passed an appid? app = appmgr.get(app_dir) - except FlipperManifestException as _: + except FlipperManifestException: # Look up path components in known app dirs for dir_part in reversed(pathlib.Path(app_dir).parts): if app := appmgr.find_by_appdir(dir_part): diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py index b4e1e58ac..1831a6984 100644 --- a/scripts/fbt_tools/fbt_hwtarget.py +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -1,5 +1,3 @@ -from SCons.Builder import Builder -from SCons.Action import Action import json diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 90d0831eb..2f7d62388 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -1,21 +1,20 @@ +import json +import os.path +import pathlib +import posixpath import shutil -from SCons.Builder import Builder + +from fbt.sdk.cache import SdkCache +from fbt.sdk.collector import SdkCollector +from fbt.util import path_as_posix from SCons.Action import Action +from SCons.Builder import Builder from SCons.Errors import UserError # from SCons.Scanner import C from SCons.Script import Entry from SCons.Util import LogicalLines -import os.path -import posixpath -import pathlib -import json - -from fbt.sdk.collector import SdkCollector -from fbt.sdk.cache import SdkCache -from fbt.util import path_as_posix - def ProcessSdkDepends(env, filename): try: diff --git a/scripts/fbt_tools/fbt_tweaks.py b/scripts/fbt_tools/fbt_tweaks.py index 700f66d23..68ac9d7d1 100644 --- a/scripts/fbt_tools/fbt_tweaks.py +++ b/scripts/fbt_tools/fbt_tweaks.py @@ -1,15 +1,13 @@ +import os +import sys +import traceback + import SCons.Warnings as Warnings +from ansi.color import fg from SCons.Errors import UserError - # from SCons.Script.Main import find_deepest_user_frame -from ansi.color import fg, bg, fx - -import traceback -import sys -import os - def find_deepest_user_frame(tb): tb.reverse() diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index 87497ca5f..8469e181a 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def version_emitter(target, source, env): diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index f510c2a60..06a435b6d 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -1,6 +1,6 @@ -from SCons.Builder import Builder -from SCons.Action import Action import SCons +from SCons.Action import Action +from SCons.Builder import Builder __OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" __NM_ARM_BIN = "arm-none-eabi-nm" diff --git a/scripts/fbt_tools/gdb.py b/scripts/fbt_tools/gdb.py index 38256a0f8..ea29e9c92 100644 --- a/scripts/fbt_tools/gdb.py +++ b/scripts/fbt_tools/gdb.py @@ -1,7 +1,3 @@ -from SCons.Builder import Builder -from SCons.Action import Action - - def generate(env): env.SetDefault( GDB="gdb", diff --git a/scripts/fbt_tools/objdump.py b/scripts/fbt_tools/objdump.py index f5fa938a7..31f817648 100644 --- a/scripts/fbt_tools/objdump.py +++ b/scripts/fbt_tools/objdump.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def generate(env): diff --git a/scripts/fbt_tools/openocd.py b/scripts/fbt_tools/openocd.py index dcf0bf925..157d798f4 100644 --- a/scripts/fbt_tools/openocd.py +++ b/scripts/fbt_tools/openocd.py @@ -1,7 +1,7 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Defaults import Touch import SCons +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Defaults import Touch __OPENOCD_BIN = "openocd" diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index 593559a33..211f46aee 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -1,11 +1,12 @@ -from SCons.Builder import Builder -from SCons.Action import Action -from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten -import multiprocessing -import webbrowser import atexit -import sys +import multiprocessing import subprocess +import sys +import webbrowser + +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Script import Delete, Flatten, GetBuildFailures, Mkdir __no_browser = False diff --git a/scripts/fbt_tools/sconsmodular.py b/scripts/fbt_tools/sconsmodular.py index 57ae8f055..4dc2079a6 100644 --- a/scripts/fbt_tools/sconsmodular.py +++ b/scripts/fbt_tools/sconsmodular.py @@ -1,5 +1,6 @@ -import posixpath import os +import posixpath + from SCons.Errors import UserError diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index fbcee965b..7dbde531b 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -1,6 +1,6 @@ import SCons -from SCons.Script import Flatten from fbt.util import GLOB_FILE_EXCLUSION +from SCons.Script import Flatten def GlobRecursive(env, pattern, node=".", exclude=[]): diff --git a/scripts/fbt_tools/strip.py b/scripts/fbt_tools/strip.py index 053956f22..ee14fc185 100644 --- a/scripts/fbt_tools/strip.py +++ b/scripts/fbt_tools/strip.py @@ -1,5 +1,5 @@ -from SCons.Builder import Builder from SCons.Action import Action +from SCons.Builder import Builder def generate(env): diff --git a/scripts/flash.py b/scripts/flash.py index fb05b8b0b..6189dc1a2 100755 --- a/scripts/flash.py +++ b/scripts/flash.py @@ -1,13 +1,9 @@ #!/usr/bin/env python3 -import logging -import argparse -import sys -import os from flipper.app import App -from flipper.cube import CubeProgrammer from flipper.assets.coprobin import CoproBinary +from flipper.cube import CubeProgrammer STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE" @@ -94,59 +90,59 @@ class Main(App): } def wipe(self): - self.logger.info(f"Wiping flash") + self.logger.info("Wiping flash") cp = CubeProgrammer(self._getCubeParams()) - self.logger.info(f"Setting RDP to 0xBB") + self.logger.info("Setting RDP to 0xBB") cp.setOptionBytes({"RDP": ("0xBB", "rw")}) - self.logger.info(f"Verifying RDP") + self.logger.info("Verifying RDP") r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")}) - assert r == True + assert r is True self.logger.info(f"Result: {r}") - self.logger.info(f"Setting RDP to 0xAA") + self.logger.info("Setting RDP to 0xAA") cp.setOptionBytes({"RDP": ("0xAA", "rw")}) - self.logger.info(f"Verifying RDP") + self.logger.info("Verifying RDP") r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")}) - assert r == True + assert r is True self.logger.info(f"Result: {r}") - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core1bootloader(self): - self.logger.info(f"Flashing bootloader") + self.logger.info("Flashing bootloader") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) - self.logger.info(f"Complete") + self.logger.info("Complete") cp.resetTarget() return 0 def core1firmware(self): - self.logger.info(f"Flashing firmware") + self.logger.info("Flashing firmware") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08008000", self.args.firmware) - self.logger.info(f"Complete") + self.logger.info("Complete") cp.resetTarget() return 0 def core1(self): - self.logger.info(f"Flashing bootloader") + self.logger.info("Flashing bootloader") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) - self.logger.info(f"Flashing firmware") + self.logger.info("Flashing firmware") cp.flashBin("0x08008000", self.args.firmware) cp.resetTarget() - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core2fus(self): if self.args.statement != STATEMENT: self.logger.error( - f"PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" + "PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" ) return 1 - self.logger.info(f"Flashing Firmware Update Service") + self.logger.info("Flashing Firmware Update Service") cp = CubeProgrammer(self._getCubeParams()) cp.flashCore2(self.args.fus_address, self.args.fus) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 def core2radio(self): @@ -163,15 +159,15 @@ class Main(App): f"Radio address not provided, guessed as 0x{radio_address:X}" ) if radio_address > 0x080E0000: - self.logger.error(f"I KNOW WHAT YOU DID LAST SUMMER") + self.logger.error("I KNOW WHAT YOU DID LAST SUMMER") return 1 cp = CubeProgrammer(self._getCubeParams()) - self.logger.info(f"Removing Current Radio Stack") + self.logger.info("Removing Current Radio Stack") cp.deleteCore2RadioStack() - self.logger.info(f"Flashing Radio Stack") + self.logger.info("Flashing Radio Stack") cp.flashCore2(radio_address, self.args.radio) - self.logger.info(f"Complete") + self.logger.info("Complete") return 0 diff --git a/scripts/flipper/app.py b/scripts/flipper/app.py index 30630a5f9..405c4c399 100644 --- a/scripts/flipper/app.py +++ b/scripts/flipper/app.py @@ -44,7 +44,7 @@ class App: if isinstance(return_code, int): return self._exit(return_code) else: - self.logger.error(f"Missing return code") + self.logger.error("Missing return code") return self._exit(255) def _exit(self, code): diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index e0375b51f..ee13a9b5e 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -6,7 +6,7 @@ import xml.etree.ElementTree as ET import posixpath import os -from flipper.utils import * +from flipper.utils import file_sha256, timestamp from flipper.assets.coprobin import CoproBinary, get_stack_type @@ -45,13 +45,13 @@ class Copro: cube_manifest = ET.parse(cube_manifest_file) cube_package = cube_manifest.find("PackDescription") if not cube_package: - raise Exception(f"Unknown Cube manifest format") + raise Exception("Unknown Cube manifest format") cube_version = cube_package.get("Patch") or cube_package.get("Release") if not cube_version or not cube_version.startswith("FW.WB"): - raise Exception(f"Incorrect Cube package or version info") + raise Exception("Incorrect Cube package or version info") cube_version = cube_version.replace("FW.WB.", "", 1) if cube_version != reference_cube_version: - raise Exception(f"Unsupported cube version") + raise Exception("Unsupported cube version") self.version = cube_version def _getFileName(self, name): diff --git a/scripts/flipper/assets/coprobin.py b/scripts/flipper/assets/coprobin.py index 64f0b8c87..7c5bdb3dc 100644 --- a/scripts/flipper/assets/coprobin.py +++ b/scripts/flipper/assets/coprobin.py @@ -1,6 +1,7 @@ import struct import math -import os, os.path +import os +import os.path import sys diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index cbd1320b6..ebe9fd889 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -1,13 +1,11 @@ import multiprocessing import logging import os -import sys -import shutil from collections import Counter -from flipper.utils.fff import * -from flipper.utils.templite import * -from .icon import * +from flipper.utils.fff import FlipperFormatFile +from flipper.utils.templite import Templite +from .icon import ImageTools, file2image def _convert_image_to_bm(pair: set): @@ -121,7 +119,7 @@ class DolphinBubbleAnimation: self.meta["Passive frames"] + self.meta["Active frames"] == ordered_frames_count ) - except EOFError as e: + except EOFError: raise Exception("Invalid meta file: too short") except AssertionError as e: self.logger.exception(e) @@ -158,7 +156,7 @@ class DolphinBubbleAnimation: except AssertionError as e: self.logger.exception(e) self.logger.error( - f"Animation {self.name} bubble slot {bubble_slot} got incorrect data: {bubble}" + f"Animation {self.name} bubble slot {bubble['Slot']} got incorrect data: {bubble}" ) raise Exception("Meta file is invalid: incorrect bubble data") except EOFError: diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index f0dae25be..d5d2a585e 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -1,9 +1,6 @@ import logging -import argparse import subprocess import io -import os -import sys ICONS_SUPPORTED_FORMATS = ["png"] @@ -36,11 +33,8 @@ class ImageTools: @staticmethod def is_processing_slow(): try: - from PIL import Image, ImageOps - import heatshrink2 - return False - except ImportError as e: + except ImportError: return True def __init__(self): @@ -52,7 +46,7 @@ class ImageTools: try: from PIL import Image, ImageOps - except ImportError as e: + except ImportError: self.__pil_unavailable = True self.logger.info("pillow module is missing, using convert cli util") return self.png2xbm(file) @@ -72,7 +66,7 @@ class ImageTools: try: import heatshrink2 - except ImportError as e: + except ImportError: self.__hs2_unavailable = True self.logger.info("heatshrink2 module is missing, using heatshrink cli util") return self.xbm2hs(data) diff --git a/scripts/flipper/assets/manifest.py b/scripts/flipper/assets/manifest.py index a8f6855a4..a9bbb8dac 100644 --- a/scripts/flipper/assets/manifest.py +++ b/scripts/flipper/assets/manifest.py @@ -1,11 +1,10 @@ -import datetime import logging import os import posixpath from pathlib import Path -from flipper.utils import * -from flipper.utils.fstree import * +from flipper.utils import timestamp, file_md5 +from flipper.utils.fstree import FsNode, compare_fs_trees MANIFEST_VERSION = 0 diff --git a/scripts/flipper/assets/obdata.py b/scripts/flipper/assets/obdata.py index 0f7f5c192..eb35d0e17 100644 --- a/scripts/flipper/assets/obdata.py +++ b/scripts/flipper/assets/obdata.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -import logging -import struct from enum import Enum from dataclasses import dataclass @@ -181,7 +179,7 @@ class OptionBytesData: def gen_values(self): obref = ObReferenceValuesGenerator() - converted_refs = list(obref.apply(ob) for ob in self.obs) + list(obref.apply(ob) for ob in self.obs) return obref diff --git a/scripts/flipper/cube.py b/scripts/flipper/cube.py index 38aa54a85..e4f9876df 100644 --- a/scripts/flipper/cube.py +++ b/scripts/flipper/cube.py @@ -14,7 +14,7 @@ class CubeProgrammer: if "port" in config and config["port"]: connect.append(f"port={config['port']}") else: - connect.append(f"port=swd") + connect.append("port=swd") if "serial" in config and config["serial"]: connect.append(f"sn={config['serial']}") self.params.append("-c " + " ".join(connect)) @@ -43,20 +43,20 @@ class CubeProgrammer: return output.decode() def getVersion(self): - output = self._execute(["--version"]) + self._execute(["--version"]) def checkOptionBytes(self, option_bytes): output = self._execute(["-ob displ"]) ob_correct = True for line in output.split("\n"): line = line.strip() - if not ":" in line: + if ":" not in line: self.logger.debug(f"Skipping line: {line}") continue key, data = line.split(":", 1) key = key.strip() data = data.strip() - if not key in option_bytes.keys(): + if key not in option_bytes.keys(): self.logger.debug(f"Skipping key: {key}") continue self.logger.debug(f"Processing key: {key} {data}") diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index cff32ceb1..9f6f52156 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -151,7 +151,7 @@ class FlipperStorage: try: # TODO: better decoding, considering non-ascii characters line = line.decode("ascii") - except: + except Exception: continue line = line.strip() @@ -194,7 +194,7 @@ class FlipperStorage: try: # TODO: better decoding, considering non-ascii characters line = line.decode("ascii") - except: + except Exception: continue line = line.strip() diff --git a/scripts/flipper/utils/__init__.py b/scripts/flipper/utils/__init__.py index 62bf98a25..6b4ebbd52 100644 --- a/scripts/flipper/utils/__init__.py +++ b/scripts/flipper/utils/__init__.py @@ -1,6 +1,5 @@ import datetime import hashlib -import os def timestamp(): diff --git a/scripts/flipper/utils/programmer_openocd.py b/scripts/flipper/utils/programmer_openocd.py index 3d2171854..5a8029f37 100644 --- a/scripts/flipper/utils/programmer_openocd.py +++ b/scripts/flipper/utils/programmer_openocd.py @@ -31,13 +31,13 @@ class OpenOCDProgrammer(Programmer): config["interface"] = interface config["target"] = "target/stm32wbx.cfg" - if not serial is None: + if serial is not None: if interface == "interface/cmsis-dap.cfg": config["serial"] = f"cmsis_dap_serial {serial}" elif "stlink" in interface: config["serial"] = f"stlink_serial {serial}" - if not port_base is None: + if port_base is not None: config["port_base"] = port_base self.openocd = OpenOCD(config) @@ -59,7 +59,7 @@ class OpenOCDProgrammer(Programmer): raise Exception(f"File {file_path} not found") self.openocd.start() - self.openocd.send_tcl(f"init") + self.openocd.send_tcl("init") self.openocd.send_tcl( f"program {file_path} 0x{address:08x}{' verify' if verify else ''} reset exit" ) @@ -196,7 +196,7 @@ class OpenOCDProgrammer(Programmer): if ob_need_to_apply: stm32.option_bytes_apply(self.openocd) else: - self.logger.info(f"Option Bytes are already correct") + self.logger.info("Option Bytes are already correct") # Load Option Bytes # That will reset and also lock the Option Bytes and the Flash @@ -256,7 +256,7 @@ class OpenOCDProgrammer(Programmer): already_written = False if already_written: - self.logger.info(f"OTP memory is already written with the given data") + self.logger.info("OTP memory is already written with the given data") return OpenOCDProgrammerResult.Success self.reset(self.RunMode.Stop) diff --git a/scripts/flipper/utils/stm32wb55.py b/scripts/flipper/utils/stm32wb55.py index 910b0d7d6..52a5ec4e3 100644 --- a/scripts/flipper/utils/stm32wb55.py +++ b/scripts/flipper/utils/stm32wb55.py @@ -123,7 +123,7 @@ class STM32WB55: def clear_flash_errors(self, oocd: OpenOCD): # Errata 2.2.9: Flash OPTVERR flag is always set after system reset # And also clear all other flash error flags - self.logger.debug(f"Resetting flash errors") + self.logger.debug("Resetting flash errors") self.FLASH_SR.load(oocd) self.FLASH_SR.OP_ERR = 1 self.FLASH_SR.PROG_ERR = 1 @@ -218,7 +218,7 @@ class STM32WB55: raise Exception("Flash lock failed") def option_bytes_apply(self, oocd: OpenOCD): - self.logger.debug(f"Applying Option Bytes") + self.logger.debug("Applying Option Bytes") self.FLASH_CR.load(oocd) self.FLASH_CR.OPT_STRT = 1 @@ -228,7 +228,7 @@ class STM32WB55: self.flash_wait_for_operation(oocd) def option_bytes_load(self, oocd: OpenOCD): - self.logger.debug(f"Loading Option Bytes") + self.logger.debug("Loading Option Bytes") self.FLASH_CR.load(oocd) self.FLASH_CR.OBL_LAUNCH = 1 self.FLASH_CR.store(oocd) diff --git a/scripts/flipper/utils/templite.py b/scripts/flipper/utils/templite.py index 2d958bd77..1d19585cd 100644 --- a/scripts/flipper/utils/templite.py +++ b/scripts/flipper/utils/templite.py @@ -77,8 +77,8 @@ class TempliteCompiler: return lines = self.block.splitlines() - margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip()) - self.block = "\n".join("\t" * self.offset + l[margin:] for l in lines) + margin = min(len(line) - len(line.lstrip()) for line in lines if line.strip()) + self.block = "\n".join("\t" * self.offset + line[margin:] for line in lines) self.blocks.append(self.block) if self.block.endswith(":"): self.offset += 1 diff --git a/scripts/fwsize.py b/scripts/fwsize.py index 445c29049..75a825692 100644 --- a/scripts/fwsize.py +++ b/scripts/fwsize.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -from flipper.app import App -import subprocess -import os import math +import os +import subprocess + from ansi.color import fg +from flipper.app import App class Main(App): diff --git a/scripts/get_env.py b/scripts/get_env.py index 92f9243c2..5403bafeb 100644 --- a/scripts/get_env.py +++ b/scripts/get_env.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 -import ssl -import json -import os -import shlex -import re -import string -import random import argparse import datetime +import json +import os +import random +import re +import shlex +import ssl +import string import urllib.request diff --git a/scripts/lint.py b/scripts/lint.py index 58f2d69f5..8530209be 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 +import multiprocessing import os import re import shutil import subprocess -import multiprocessing from flipper.app import App - SOURCE_CODE_FILE_EXTENSIONS = [".h", ".c", ".cpp", ".cxx", ".hpp"] SOURCE_CODE_FILE_PATTERN = r"^[0-9A-Za-z_]+\.[a-z]+$" SOURCE_CODE_DIR_PATTERN = r"^[0-9A-Za-z_]+$" @@ -59,7 +58,7 @@ class Main(App): show_message = True if show_message: self.logger.warning( - f"Folders are not renamed automatically, please fix it by yourself" + "Folders are not renamed automatically, please fix it by yourself" ) def _find_sources(self, folders: list): @@ -70,7 +69,7 @@ class Main(App): for filename in filenames: ext = os.path.splitext(filename.lower())[1] - if not ext in SOURCE_CODE_FILE_EXTENSIONS: + if ext not in SOURCE_CODE_FILE_EXTENSIONS: continue output.append(os.path.join(dirpath, filename)) return output @@ -80,7 +79,7 @@ class Main(App): try: subprocess.check_call(task) return True - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: return False def _format_sources(self, sources: list, dry_run: bool = False): @@ -144,7 +143,7 @@ class Main(App): def _apply_file_permissions(self, sources: list, dry_run: bool = False): execute_permissions = 0o111 - pattern = re.compile(SOURCE_CODE_FILE_PATTERN) + re.compile(SOURCE_CODE_FILE_PATTERN) good = [] bad = [] # Check sources for unexpected execute permissions diff --git a/scripts/merge_report_qa.py b/scripts/merge_report_qa.py index caa742408..a33327e6b 100755 --- a/scripts/merge_report_qa.py +++ b/scripts/merge_report_qa.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 +import argparse import os import re import sys -import argparse + from slack_sdk import WebClient from slack_sdk.errors import SlackApiError diff --git a/scripts/meta.py b/scripts/meta.py index ae2f213b7..f47ef65fb 100755 --- a/scripts/meta.py +++ b/scripts/meta.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -from flipper.app import App import json +from flipper.app import App + class Main(App): def init(self): diff --git a/scripts/ob.py b/scripts/ob.py index 178fe16a7..7010bdec5 100755 --- a/scripts/ob.py +++ b/scripts/ob.py @@ -44,7 +44,7 @@ class Main(App): ) def check(self): - self.logger.info(f"Checking Option Bytes") + self.logger.info("Checking Option Bytes") # OpenOCD openocd = OpenOCDProgrammer( @@ -60,7 +60,7 @@ class Main(App): return return_code def set(self): - self.logger.info(f"Setting Option Bytes") + self.logger.info("Setting Option Bytes") # OpenOCD openocd = OpenOCDProgrammer( diff --git a/scripts/otp.py b/scripts/otp.py index cb76bdc86..19b8c4df4 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 +import datetime import logging -import argparse -import subprocess import os -import sys import re import struct -import datetime + +from flipper.app import App +from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult OTP_MAGIC = 0xBABE OTP_VERSION = 0x02 @@ -33,9 +33,6 @@ OTP_DISPLAYS = { "mgg": 0x02, } -from flipper.app import App -from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult - class OTPException(Exception): def __init__(self, message: str, result: OpenOCDProgrammerResult): @@ -158,7 +155,7 @@ class Main(App): ) def generate_all(self): - self.logger.info(f"Generating OTP") + self.logger.info("Generating OTP") self._processFirstArgs() self._processSecondArgs() with open(f"{self.args.file}_first.bin", "wb") as file: @@ -172,18 +169,18 @@ class Main(App): return 0 def flash_first(self): - self.logger.info(f"Flashing first block of OTP") + self.logger.info("Flashing first block of OTP") self._processFirstArgs() filename = f"otp_unknown_first_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packFirst()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -195,7 +192,7 @@ class Main(App): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() @@ -205,18 +202,18 @@ class Main(App): return 0 def flash_second(self): - self.logger.info(f"Flashing second block of OTP") + self.logger.info("Flashing second block of OTP") self._processSecondArgs() filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packSecond()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -228,7 +225,7 @@ class Main(App): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() @@ -238,7 +235,7 @@ class Main(App): return 0 def flash_all(self): - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") self._processFirstArgs() self._processSecondArgs() @@ -246,12 +243,12 @@ class Main(App): filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" try: - self.logger.info(f"Packing binary data") + self.logger.info("Packing binary data") with open(filename, "wb") as file: file.write(self._packFirst()) file.write(self._packSecond()) - self.logger.info(f"Flashing OTP") + self.logger.info("Flashing OTP") openocd = OpenOCDProgrammer( self.args.interface, @@ -263,7 +260,7 @@ class Main(App): if programmer_result != OpenOCDProgrammerResult.Success: raise OTPException("Failed to flash OTP", programmer_result) - self.logger.info(f"Flashed Successfully") + self.logger.info("Flashed Successfully") except OTPException as e: self.logger.exception(e) return e.get_exit_code() diff --git a/scripts/program.py b/scripts/program.py index c140a9024..f3e7e3e2d 100755 --- a/scripts/program.py +++ b/scripts/program.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 -import typing -import subprocess import logging -import time import os import socket - +import subprocess +import time +import typing from abc import ABC, abstractmethod from dataclasses import dataclass + from flipper.app import App @@ -223,7 +223,7 @@ class BlackmagicProgrammer(Programmer): try: socket.inet_aton(address) return True - except: + except Exception: return False def set_serial(self, serial: str): @@ -415,12 +415,12 @@ class Main(App): if len(interfaces) == 0: interfaces = [p for p in network_programmers if p.get_name() == i_name] else: - self.logger.info(f"Probing for interfaces...") + self.logger.info("Probing for interfaces...") interfaces = self._search_interface(self.args.serial) if len(interfaces) == 0: # Probe network blackmagic - self.logger.info(f"Probing for network interfaces...") + self.logger.info("Probing for network interfaces...") interfaces = self._search_network_interface(self.args.serial) if len(interfaces) == 0: diff --git a/scripts/runfap.py b/scripts/runfap.py index f8ff607c1..a240acf12 100644 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 +import operator +from functools import reduce + from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.utils.cdc import resolve_port -import os -import posixpath -from functools import reduce -import operator - class Main(App): def init(self): @@ -38,8 +36,8 @@ class Main(App): self.parser.set_defaults(func=self.install) @staticmethod - def flatten(l): - return reduce(operator.concat, l, []) + def flatten(item_list): + return reduce(operator.concat, item_list, []) def install(self): self.args.sources = self.flatten(self.args.sources) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index af2554d0a..1657feab9 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -5,7 +5,7 @@ import shutil import tarfile import zipfile from os import makedirs, walk -from os.path import exists, join, relpath, basename, split +from os.path import basename, exists, join, relpath from ansi.color import fg from flipper.app import App diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py index 9bfbfefa3..1ce0b8376 100644 --- a/scripts/selfupdate.py +++ b/scripts/selfupdate.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 -from typing import final -from flipper.app import App -from flipper.storage import FlipperStorage, FlipperStorageOperations -from flipper.utils.cdc import resolve_port - import logging import os import pathlib -import serial.tools.list_ports as list_ports + +from flipper.app import App +from flipper.storage import FlipperStorage, FlipperStorageOperations +from flipper.utils.cdc import resolve_port class Main(App): @@ -54,7 +52,7 @@ class Main(App): f"update install {flipper_update_path}/{manifest_name}\r" ) result = storage.read.until(storage.CLI_EOL) - if not b"Verifying" in result: + if b"Verifying" not in result: self.logger.error(f"Unexpected response: {result.decode('ascii')}") return 3 result = storage.read.until(storage.CLI_EOL) diff --git a/scripts/serial_cli.py b/scripts/serial_cli.py index 390b1f263..2fa37d751 100644 --- a/scripts/serial_cli.py +++ b/scripts/serial_cli.py @@ -1,9 +1,10 @@ import logging -import subprocess -from flipper.utils.cdc import resolve_port import os +import subprocess import sys +from flipper.utils.cdc import resolve_port + def main(): logger = logging.getLogger() diff --git a/scripts/storage.py b/scripts/storage.py index 84c01021a..e04eaa7e1 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 +import binascii +import filecmp +import os +import tempfile + from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.utils.cdc import resolve_port -import os -import binascii -import filecmp -import tempfile - def WrapStorageOp(func): def wrapper(*args, **kwargs): @@ -122,7 +122,7 @@ class Main(App): try: print("Text data:") print(data.decode()) - except: + except Exception: print("Binary hexadecimal data:") print(binascii.hexlify(data).decode()) diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index ce7c8b978..fdb51981b 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -1,7 +1,6 @@ from SCons.Platform import TempFileMunge from SCons.Node import FS from SCons.Errors import UserError -from SCons.Warnings import warn, WarningOnByDefault import os @@ -14,6 +13,7 @@ SetOption("max_drift", 1) ufbt_state_dir = Dir(os.environ.get("UFBT_STATE_DIR", "#.ufbt")) ufbt_script_dir = Dir(os.environ.get("UFBT_SCRIPT_DIR")) +ufbt_build_dir = ufbt_state_dir.Dir("build") ufbt_current_sdk_dir = ufbt_state_dir.Dir("current") @@ -63,16 +63,7 @@ core_env = Environment( ], ) -if "update" in BUILD_TARGETS: - SConscript( - "update.scons", - exports={"core_env": core_env}, - ) - -if "purge" in BUILD_TARGETS: - core_env.Execute(Delete(ufbt_state_dir)) - print("uFBT state purged") - Exit(0) +core_env.Append(CPPDEFINES=GetOption("extra_defines")) # Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state @@ -109,7 +100,7 @@ env = core_env.Clone( "fbt_assets", ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ], - FBT_FAP_DEBUG_ELF_ROOT=ufbt_state_dir.Dir("build"), + FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", @@ -427,3 +418,25 @@ dist_env.PhonyTarget( "get_apiversion", "@echo $( ${UFBT_API_VERSION} $)", ) + +# Dolphin animation builder. Expects "external" directory in current dir +# with animation sources & manifests. Builds & uploads them to connected Flipper +dolphin_src_dir = original_app_dir.Dir("external") +if dolphin_src_dir.exists(): + dolphin_dir = ufbt_build_dir.Dir("dolphin") + dolphin_external = dist_env.DolphinExtBuilder( + ufbt_build_dir.Dir("dolphin"), + original_app_dir, + DOLPHIN_RES_TYPE="external", + ) + dist_env.PhonyTarget( + "dolphin_ext", + '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py send "${SOURCE}" /ext/dolphin', + source=ufbt_build_dir.Dir("dolphin"), + ) +else: + + def missing_dolphin_folder(**kw): + raise UserError(f"Dolphin folder not found: {dolphin_src_dir}") + + dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None)) diff --git a/scripts/ufbt/commandline.scons b/scripts/ufbt/commandline.scons index 9af5e9bce..a9b91bbca 100644 --- a/scripts/ufbt/commandline.scons +++ b/scripts/ufbt/commandline.scons @@ -1,32 +1,18 @@ +AddOption( + "--extra-define", + action="append", + dest="extra_defines", + default=[], + help="Extra global define that will be passed to C/C++ compiler, can be specified multiple times", +) + AddOption( "--proxy-env", action="store", dest="proxy_env", default="", - help="Comma-separated list of additional environment variables to pass to child SCons processes", -) - -AddOption( - "--channel", - action="store", - dest="sdk_channel", - choices=["dev", "rc", "release"], - default="", - help="Release channel to use for SDK", -) - -AddOption( - "--branch", - action="store", - dest="sdk_branch", - help="Custom main repo branch to use for SDK", -) - -AddOption( - "--hw-target", - action="store", - dest="sdk_target", - help="SDK Hardware target", + help="Comma-separated list of additional environment variables to pass to " + "child SCons processes", ) vars = Variables("ufbt_options.py", ARGUMENTS) diff --git a/scripts/ufbt/site_init.py b/scripts/ufbt/site_init.py index 557085ede..8e38a36e9 100644 --- a/scripts/ufbt/site_init.py +++ b/scripts/ufbt/site_init.py @@ -1,8 +1,8 @@ -from SCons.Script import GetBuildFailures -import SCons.Errors - import atexit + +import SCons.Errors from ansi.color import fg, fx +from SCons.Script import GetBuildFailures def bf_to_str(bf): diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py index 76c6e9acf..47f4afec4 100644 --- a/scripts/ufbt/site_tools/ufbt_state.py +++ b/scripts/ufbt/site_tools/ufbt_state.py @@ -1,12 +1,11 @@ -from SCons.Errors import StopError -from SCons.Warnings import warn, WarningOnByDefault - import json import os -import sys import pathlib +import sys from functools import reduce +from SCons.Errors import StopError + def _load_sdk_data(sdk_root): split_vars = { diff --git a/scripts/ufbt/update.scons b/scripts/ufbt/update.scons deleted file mode 100644 index 9658e0bb2..000000000 --- a/scripts/ufbt/update.scons +++ /dev/null @@ -1,37 +0,0 @@ -from SCons.Errors import StopError - -Import("core_env") - -update_env = core_env.Clone( - toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")], - tools=["python3"], -) -print("Updating SDK...") -ufbt_state = update_env["UFBT_STATE"] - -update_args = [ - "--ufbt-dir", - f'"{update_env["UFBT_STATE_DIR"]}"', -] - -if branch_name := GetOption("sdk_branch"): - update_args.extend(["--branch", branch_name]) -elif channel_name := GetOption("sdk_channel"): - update_args.extend(["--channel", channel_name]) -elif branch_name := ufbt_state.get("branch", None): - update_args.extend(["--branch", branch_name]) -elif channel_name := ufbt_state.get("channel", None): - update_args.extend(["--channel", channel_name]) -else: - raise StopError("No branch or channel specified for SDK update") - -if hw_target := GetOption("sdk_target"): - update_args.extend(["--hw-target", hw_target]) -else: - update_args.extend(["--hw-target", ufbt_state["hw_target"]]) - -update_env.Replace(UPDATE_ARGS=update_args) -result = update_env.Execute( - update_env.subst('$PYTHON3 "$UFBT_BOOTSTRAP_SCRIPT" $UPDATE_ARGS'), -) -Exit(result) diff --git a/scripts/update.py b/scripts/update.py index 2b0157260..0f3ee6ea8 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -1,16 +1,16 @@ #!/usr/bin/env python3 -from flipper.app import App -from flipper.utils.fff import FlipperFormatFile -from flipper.assets.coprobin import CoproBinary, get_stack_type -from flipper.assets.obdata import OptionBytesData, ObReferenceValues -from os.path import basename, join, exists +import math import os import shutil -import zlib import tarfile -import math +import zlib +from os.path import exists, join +from flipper.app import App +from flipper.assets.coprobin import CoproBinary, get_stack_type +from flipper.assets.obdata import ObReferenceValues, OptionBytesData +from flipper.utils.fff import FlipperFormatFile from slideshow import Main as SlideshowMain @@ -267,9 +267,9 @@ class Main(App): @staticmethod def batch(iterable, n=1): - l = len(iterable) - for ndx in range(0, l, n): - yield iterable[ndx : min(ndx + n, l)] + iterable_len = len(iterable) + for ndx in range(0, iterable_len, n): + yield iterable[ndx : min(ndx + n, iterable_len)] if __name__ == "__main__": diff --git a/scripts/version.py b/scripts/version.py index 880a97281..71d201abb 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,12 +1,12 @@ #!/usb/bin/env python3 -from flipper.app import App - -import subprocess -import os import json +import os +import subprocess from datetime import date, datetime +from flipper.app import App + class GitVersion: REVISION_SUFFIX_LENGTH = 8 diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 89ee49242..6db0e538d 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -1,12 +1,12 @@ from dataclasses import dataclass, field +from fbt.appmanifest import FlipperAppType from SCons.Node import NodeList from SCons.Warnings import warn, WarningOnByDefault -from SCons.Errors import UserError + Import("ENV") -from fbt.appmanifest import FlipperAppType appenv = ENV["APPENV"] = ENV.Clone( tools=[ From 71e85ac36723663f1d153d46f682245d8ed4a58d Mon Sep 17 00:00:00 2001 From: Raymond Lucke Date: Wed, 3 May 2023 02:38:09 -0400 Subject: [PATCH 111/216] Add HID mouse auto-clicker. (#2627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add HID mouse auto-clicker. * Add click rate adjustment to HID auto-clicker. * Fix formatting. * HidRemote: modify jiggler/clicker event filter and allow repeat to change click rate --------- Co-authored-by: あく --- applications/external/hid_app/hid.c | 22 ++ applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../hid_app/views/hid_mouse_clicker.c | 214 ++++++++++++++++++ .../hid_app/views/hid_mouse_clicker.h | 14 ++ .../hid_app/views/hid_mouse_jiggler.c | 2 +- 6 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.c create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index 949ff63b3..a4f64589d 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -11,6 +11,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexMedia, HidSubmenuIndexTikTok, HidSubmenuIndexMouse, + HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, }; @@ -32,6 +33,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexTikTok) { app->view_id = BtHidViewTikTok; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); + } else if(index == HidSubmenuIndexMouseClicker) { + app->view_id = HidViewMouseClicker; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); @@ -53,6 +57,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); + hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); hid_tiktok_set_connected_status(hid->hid_tiktok, connected); } @@ -114,6 +119,12 @@ Hid* hid_alloc(HidTransport transport) { hid_submenu_callback, app); } + submenu_add_item( + app->device_type_submenu, + "Mouse Clicker", + HidSubmenuIndexMouseClicker, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Mouse Jiggler", @@ -172,6 +183,15 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); + // Mouse clicker view + app->hid_mouse_clicker = hid_mouse_clicker_alloc(app); + view_set_previous_callback( + hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewMouseClicker, + hid_mouse_clicker_get_view(app->hid_mouse_clicker)); + // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( @@ -205,6 +225,8 @@ void hid_free(Hid* app) { hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); hid_mouse_free(app->hid_mouse); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker); + hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 8ed1664a3..49d8b4e04 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -20,6 +20,7 @@ #include "views/hid_keyboard.h" #include "views/hid_media.h" #include "views/hid_mouse.h" +#include "views/hid_mouse_clicker.h" #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" @@ -43,6 +44,7 @@ struct Hid { HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; + HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; HidTikTok* hid_tiktok; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 2a44832e1..1bea3355e 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -4,6 +4,7 @@ typedef enum { HidViewKeyboard, HidViewMedia, HidViewMouse, + HidViewMouseClicker, HidViewMouseJiggler, BtHidViewTikTok, HidViewExitConfirm, diff --git a/applications/external/hid_app/views/hid_mouse_clicker.c b/applications/external/hid_app/views/hid_mouse_clicker.c new file mode 100644 index 000000000..d85affc43 --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.c @@ -0,0 +1,214 @@ +#include "hid_mouse_clicker.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidMouseClicker" +#define DEFAULT_CLICK_RATE 1 +#define MAXIMUM_CLICK_RATE 60 + +struct HidMouseClicker { + View* view; + Hid* hid; + FuriTimer* timer; +}; + +typedef struct { + bool connected; + bool running; + int rate; + HidTransport transport; +} HidMouseClickerModel; + +static void hid_mouse_clicker_start_or_restart_timer(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + if(furi_timer_is_running(hid_mouse_clicker->timer)) { + furi_timer_stop(hid_mouse_clicker->timer); + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + furi_timer_start( + hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate); + }, + true); +} + +static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidMouseClickerModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker"); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->running) { + canvas_set_font(canvas, FontPrimary); + + FuriString* rate_label = furi_string_alloc(); + furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate); + elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label)); + canvas_set_font(canvas, FontSecondary); + furi_string_free(rate_label); + + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking"); + canvas_set_font(canvas, FontSecondary); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + if(model->running) { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + } else { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + } + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); +} + +static void hid_mouse_clicker_timer_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + if(model->running) { + hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + } + }, + false); +} + +static void hid_mouse_clicker_enter_callback(void* context) { + hid_mouse_clicker_start_or_restart_timer(context); +} + +static void hid_mouse_clicker_exit_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + furi_timer_stop(hid_mouse_clicker->timer); +} + +static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + bool consumed = false; + bool rate_changed = false; + + if(event->type != InputTypeShort && event->type != InputTypeRepeat) { + return false; + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + switch(event->key) { + case InputKeyOk: + model->running = !model->running; + consumed = true; + break; + case InputKeyUp: + if(model->rate < MAXIMUM_CLICK_RATE) { + model->rate++; + } + rate_changed = true; + consumed = true; + break; + case InputKeyDown: + if(model->rate > 1) { + model->rate--; + } + rate_changed = true; + consumed = true; + break; + default: + consumed = true; + break; + } + }, + true); + + if(rate_changed) { + hid_mouse_clicker_start_or_restart_timer(context); + } + + return consumed; +} + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) { + HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker)); + + hid_mouse_clicker->view = view_alloc(); + view_set_context(hid_mouse_clicker->view, hid_mouse_clicker); + view_allocate_model( + hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel)); + view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback); + view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback); + view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback); + view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback); + + hid_mouse_clicker->hid = hid; + + hid_mouse_clicker->timer = furi_timer_alloc( + hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker); + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + model->transport = hid->transport; + model->rate = DEFAULT_CLICK_RATE; + }, + true); + + return hid_mouse_clicker; +} + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + + furi_timer_stop(hid_mouse_clicker->timer); + furi_timer_free(hid_mouse_clicker->timer); + + view_free(hid_mouse_clicker->view); + + free(hid_mouse_clicker); +} + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + return hid_mouse_clicker->view; +} + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) { + furi_assert(hid_mouse_clicker); + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_mouse_clicker.h b/applications/external/hid_app/views/hid_mouse_clicker.h new file mode 100644 index 000000000..d72847baa --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidMouseClicker HidMouseClicker; + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid); + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker); + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker); + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected); diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index d8f1f8928..15547eb26 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -95,7 +95,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { bool consumed = false; - if(event->key == InputKeyOk) { + if(event->type == InputTypeShort && event->key == InputKeyOk) { with_view_model( hid_mouse_jiggler->view, HidMouseJigglerModel * model, From d110a3ef262e69c7c31755f21048aa7ac4a02469 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 18:48:13 +0300 Subject: [PATCH 112/216] Update wifi marauder version --- .../external/wifi_marauder_companion/wifi_marauder_app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 89a06f904..2f8b2f9a6 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.3" +#define WIFI_MARAUDER_APP_VERSION "v0.3.4" typedef struct WifiMarauderApp WifiMarauderApp; From 30f79f838ecf5472be407aefaab27bef67f6f861 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 20:16:20 +0300 Subject: [PATCH 113/216] rename --- applications/external/hid_app/hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index 52f4708fb..f4f59b435 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -129,7 +129,7 @@ Hid* hid_alloc(HidTransport transport) { submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( - app->device_type_submenu, "Numpad keyboard", HidSubmenuIndexNumpad, hid_submenu_callback, app); + app->device_type_submenu, "Numpad", HidSubmenuIndexNumpad, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); submenu_add_item( From 6874b3b4295b68c1035845cdc7a2c4912ea5cde3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 21:53:44 +0300 Subject: [PATCH 114/216] We don't use region provision so remove 00 from about screens --- applications/services/desktop/views/desktop_view_debug.c | 3 +-- applications/settings/about/about.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index 8c72001b4..1fe957712 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -37,13 +37,12 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%d.F%dB%dC%d %s:%s %s", + "%d.F%dB%dC%d %s %s", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 7d6724dc2..49f30ef9c 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -127,13 +127,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* furi_string_cat_printf( buffer, - "%d.F%dB%dC%d %s:%s %s\n", + "%d.F%dB%dC%d %s %s\n", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); furi_string_cat_printf(buffer, "Serial Number:\n"); From 3a51b3f70c110350f5366a2755af6abb394054ef Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 3 May 2023 21:58:07 +0300 Subject: [PATCH 115/216] Update changelog --- CHANGELOG.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a861b0a0..37c6260e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,12 @@ ### New changes -* NFC: Temp fix for Detect reader not collecting nonces -* Desktop: Temp fix for old backlight bug when locking by holding up arrow -* IR: Add Sharp and Vizio to Universal TV remote -* BLE Info: Show version instead of branch -* Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) -* Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit -* Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) -* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* Docs: Update HowToInstall (by @krolchonok | PR #443) -* OFW PR 2627: Add HID mouse auto-clicker (by @rwl4) +* Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) +* Infrared: Updated universal remote assets (by @amec0e | PR #454) +* Update slideshow: Replace QR code with good old link +* OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements +* OFW: Added API version to device info +* OFW: Gui: relax some asserts in view +* OFW: Move gauge calibration to separate header, add f18 calibration +* OFW: Fix TERMINFO on Linux systems #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) From 348088e979f828c4ce1c2d43063d0f1a562e6bdd Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 21:31:01 +0100 Subject: [PATCH 116/216] Fix BadKB USB mode and BT reset --- applications/main/bad_kb/bad_kb_app.c | 6 --- .../main/bad_kb/helpers/ducky_script.c | 49 +++++++++++++++---- .../main/bad_kb/helpers/ducky_script.h | 4 ++ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c index e8b29b837..205a14022 100644 --- a/applications/main/bad_kb/bad_kb_app.c +++ b/applications/main/bad_kb/bad_kb_app.c @@ -13,12 +13,6 @@ #define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/" BAD_KB_SETTINGS_FILE_NAME -// this is the MAC address used when we do not forget paired device (BOUND STATE) -const uint8_t BAD_KB_BOUND_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN] = - {0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4}; -const uint8_t BAD_KB_EMPTY_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN] = - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static bool bad_kb_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); BadKbApp* app = context; diff --git a/applications/main/bad_kb/helpers/ducky_script.c b/applications/main/bad_kb/helpers/ducky_script.c index 71c307cdf..d41f4ea41 100644 --- a/applications/main/bad_kb/helpers/ducky_script.c +++ b/applications/main/bad_kb/helpers/ducky_script.c @@ -12,6 +12,11 @@ #include #include +const uint8_t BAD_KB_BOUND_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN] = + {0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4}; +const uint8_t BAD_KB_EMPTY_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + #define TAG "BadKB" #define WORKER_TAG TAG "Worker" @@ -383,7 +388,8 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { bad_kb->app->switch_mode_thread = NULL; } // Looking for ID or BT_ID command at first line - bool reset_bt_id = !!bad_kb->bt; + bool usb_id = false; + bool bt_id = false; if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { if(bad_kb->bt) { bad_kb->app->is_bt = false; @@ -395,11 +401,7 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { furi_thread_start(bad_kb->app->switch_mode_thread); return false; } - if(ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1])) { - furi_check(furi_hal_usb_set_config(&usb_hid, &bad_kb->hid_cfg)); - } else { - furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); - } + usb_id = ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1]); } else if(strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0) { if(!bad_kb->bt) { bad_kb->app->is_bt = true; @@ -412,12 +414,39 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { return false; } if(!bad_kb->app->bt_remember) { - reset_bt_id = !ducky_set_bt_id(bad_kb, &line_tmp[strlen(ducky_cmd_bt_id) + 1]); + bt_id = ducky_set_bt_id(bad_kb, &line_tmp[strlen(ducky_cmd_bt_id) + 1]); } } - if(reset_bt_id) { - furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, bad_kb->app->config.bt_name); - bt_set_profile_mac_address(bad_kb->bt, bad_kb->app->config.bt_mac); + + if(bad_kb->bt) { + if(!bt_id) { + const char* bt_name = bad_kb->app->config.bt_name; + const uint8_t* bt_mac = bad_kb->app->bt_remember ? + (uint8_t*)&BAD_KB_BOUND_MAC_ADDRESS : + bad_kb->app->config.bt_mac; + bool reset_name = strncmp( + bt_name, + furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard), + BAD_KB_ADV_NAME_MAX_LEN); + bool reset_mac = memcmp( + bt_mac, + furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard), + BAD_KB_MAC_ADDRESS_LEN); + if(reset_name && reset_mac) { + furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, bt_name); + } else if(reset_name) { + bt_set_profile_adv_name(bad_kb->bt, bt_name); + } + if(reset_mac) { + bt_set_profile_mac_address(bad_kb->bt, bt_mac); + } + } + } else { + if(usb_id) { + furi_check(furi_hal_usb_set_config(&usb_hid, &bad_kb->hid_cfg)); + } else { + furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); + } } storage_file_seek(script_file, 0, true); diff --git a/applications/main/bad_kb/helpers/ducky_script.h b/applications/main/bad_kb/helpers/ducky_script.h index 6a0386cf1..015586b2e 100644 --- a/applications/main/bad_kb/helpers/ducky_script.h +++ b/applications/main/bad_kb/helpers/ducky_script.h @@ -103,6 +103,10 @@ BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb); #define BAD_KB_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH #define BAD_KB_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE +// this is the MAC address used when we do not forget paired device (BOUND STATE) +extern const uint8_t BAD_KB_BOUND_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN]; +extern const uint8_t BAD_KB_EMPTY_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN]; + typedef enum { BadKbAppErrorNoFiles, BadKbAppErrorCloseRpc, From 7d152d85ff53f0ae40528938f9c45c408d7b0fe6 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 21:59:20 +0100 Subject: [PATCH 117/216] Fix webupdater nextcloud subfolder --- .github/workflow_data/webupdater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflow_data/webupdater.py b/.github/workflow_data/webupdater.py index eecbf2282..52005151a 100644 --- a/.github/workflow_data/webupdater.py +++ b/.github/workflow_data/webupdater.py @@ -5,7 +5,7 @@ if __name__ == "__main__": client = nextcloud_client.Client(os.environ["NC_HOST"]) client.login(os.environ["NC_USER"], os.environ["NC_PASS"]) file = os.environ["NC_FILE"] - path = os.environ["NC_PATH"] + file + path = os.environ["NC_PATH"] + "/" + file try: client.delete(path) except Exception: From 04324dc812f39455a91ac364f4857130cf436ef3 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 22:10:34 +0100 Subject: [PATCH 118/216] Fix hotfix script url --- .github/workflow_data/hotfix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflow_data/hotfix.py b/.github/workflow_data/hotfix.py index fd04d7151..0cc88471e 100644 --- a/.github/workflow_data/hotfix.py +++ b/.github/workflow_data/hotfix.py @@ -12,7 +12,7 @@ if __name__ == "__main__": event = json.load(f) release = requests.get( - event["repository"]["releases_url"].rsplit("{/")[0] + "latest", + event["repository"]["releases_url"].rsplit("{/")[0] + "/latest", headers={ "Accept": "application/vnd.github.v3+json", "Authorization": f"token {os.environ['GITHUB_TOKEN']}" From eaae10441f0b87a30f07de2ad0929fb6f1e70639 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 3 May 2023 22:12:44 +0100 Subject: [PATCH 119/216] Fix favorite timeout bugs with subghz --- .../main/subghz/scenes/subghz_scene_read_raw.c | 4 ++-- .../main/subghz/scenes/subghz_scene_transmitter.c | 15 +++++---------- applications/main/subghz/subghz.c | 10 ++++++---- applications/main/subghz/subghz_i.h | 3 +++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 5734a8e9f..db2cf4763 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -124,7 +124,7 @@ void subghz_scene_read_raw_on_enter(void* context) { view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); // Start sending immediately with favorites - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW)) { + if(subghz->fav_timeout) { with_view_model( subghz->subghz_read_raw->view, SubGhzReadRAWModel * model, @@ -293,7 +293,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_stop_send(subghz->subghz_read_raw); // Exit / stop with favorites - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW)) { + if(subghz->fav_timeout) { while(scene_manager_handle_back_event(subghz->scene_manager)) ; view_dispatcher_stop(subghz->view_dispatcher); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 7877e3c14..78b26688f 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -51,8 +51,6 @@ bool subghz_scene_transmitter_update_data_show(void* context) { return ret; } -FuriTimer* fav_timer = NULL; - void fav_timer_callback(void* context) { SubGhz* subghz = context; scene_manager_handle_custom_event( @@ -77,7 +75,7 @@ void subghz_scene_transmitter_on_enter(void* context) { view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTransmitter); // Auto send and exit with favorites - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTransmitter)) { + if(subghz->fav_timeout) { subghz_custom_btn_set(0); scene_manager_handle_custom_event( subghz->scene_manager, SubGhzCustomEventViewTransmitterSendStart); @@ -86,9 +84,10 @@ void subghz_scene_transmitter_on_enter(void* context) { SubGhzViewTransmitterModel * model, { model->show_button = false; }, true); - fav_timer = furi_timer_alloc(fav_timer_callback, FuriTimerTypeOnce, subghz); + subghz->fav_timer = furi_timer_alloc(fav_timer_callback, FuriTimerTypeOnce, subghz); furi_timer_start( - fav_timer, XTREME_SETTINGS()->favorite_timeout * furi_kernel_get_tick_frequency()); + subghz->fav_timer, + XTREME_SETTINGS()->favorite_timeout * furi_kernel_get_tick_frequency()); subghz->state_notifications = SubGhzNotificationStateTx; } } @@ -134,11 +133,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTransmitter)) { - if(fav_timer) { - furi_timer_stop(fav_timer); - furi_timer_free(fav_timer); - } + if(subghz->fav_timeout) { while(scene_manager_handle_back_event(subghz->scene_manager)) ; view_dispatcher_stop(subghz->view_dispatcher); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 6752b4e55..fa6e10b7a 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -474,16 +474,13 @@ int32_t subghz_app(char* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); + subghz->fav_timeout = is_favorite; if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { //Load Raw TX subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, is_favorite); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneTransmitter, is_favorite); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); } } else { @@ -512,6 +509,11 @@ int32_t subghz_app(char* p) { view_dispatcher_run(subghz->view_dispatcher); + if(subghz->fav_timer) { + furi_timer_stop(subghz->fav_timer); + furi_timer_free(subghz->fav_timer); + } + furi_hal_power_suppress_charge_exit(); // Disable power for External CC1101 if it was enabled and module is connected furi_hal_subghz_disable_ext_power(); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index faae35fa2..37318580f 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -131,6 +131,9 @@ struct SubGhz { SubGhzDecodeRawState decode_raw_state; SubGhzFileEncoderWorker* decode_raw_file_worker_encoder; + bool fav_timeout; + FuriTimer* fav_timer; + void* rpc_ctx; }; From ee94d48736a892b5168e5b16680dcc48296b1134 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 4 May 2023 01:17:58 +0100 Subject: [PATCH 120/216] Fix lockscreen backlight flicker --- applications/services/desktop/desktop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 45435411a..127afdcdb 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -133,7 +133,6 @@ void desktop_lock(Desktop* desktop) { scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); - notification_message(desktop->notification, &sequence_display_backlight_off_delay_1000); } void desktop_unlock(Desktop* desktop) { From 0e28cfc50bbbecc52d6c07c6f29828ecdf050863 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 4 May 2023 02:12:19 +0100 Subject: [PATCH 121/216] Fix hotfix script --- .github/workflows/hotfix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/hotfix.yml b/.github/workflows/hotfix.yml index 505f9c676..85bf00171 100644 --- a/.github/workflows/hotfix.yml +++ b/.github/workflows/hotfix.yml @@ -55,6 +55,8 @@ jobs: - name: "Upload hotfix" run: python .github/workflow_data/hotfix.py + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - name: "Merge pull request" uses: "pascalgn/automerge-action@v0.15.6" From dbade67dc4663568c948c75b96e02ee05eaa043f Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 4 May 2023 03:17:44 +0100 Subject: [PATCH 122/216] Bump hotfix version --- fbt_options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbt_options.py b/fbt_options.py index 5c874357a..3fdcc6e30 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -14,7 +14,7 @@ DEBUG = 0 # Suffix to add to files when building distribution # If OS environment has DIST_SUFFIX set, it will be used instead -DIST_SUFFIX = "XFW-0045_02052023" +DIST_SUFFIX = "XFW-0045_04052023" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" From 103abfef86a90fd9ea9709b28aa4a9bfb3f48f65 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 4 May 2023 03:18:52 +0100 Subject: [PATCH 123/216] Fix hotfix script again --- .github/workflow_data/hotfix.py | 43 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/.github/workflow_data/hotfix.py b/.github/workflow_data/hotfix.py index 0cc88471e..cb454ae56 100644 --- a/.github/workflow_data/hotfix.py +++ b/.github/workflow_data/hotfix.py @@ -19,30 +19,30 @@ if __name__ == "__main__": } ).json() - artifacts = ( - os.environ['ARTIFACT_TGZ'], - os.environ['ARTIFACT_ZIP'] - ) + artifacts = { + os.environ['ARTIFACT_TGZ']: "application/gzip", + os.environ['ARTIFACT_ZIP']: "application/zip" + } for asset in release["assets"]: - if asset["name"] in artifacts: - req = requests.delete( - asset["url"], - headers={ - "Accept": "application/vnd.github.v3+json", - "Authorization": f"token {os.environ['GITHUB_TOKEN']}" - } - ) - if not req.ok: - print(f"{req.url = }\n{req.status_code = }\n{req.content = }") - sys.exit(1) + req = requests.delete( + asset["url"], + headers={ + "Accept": "application/vnd.github.v3+json", + "Authorization": f"token {os.environ['GITHUB_TOKEN']}" + } + ) + if not req.ok: + print(f"{req.url = }\n{req.status_code = }\n{req.content = }") + sys.exit(1) - for artifact in artifacts: + for artifact, mediatype in artifacts.items(): req = requests.post( release["upload_url"].rsplit("{?", 1)[0], headers={ "Accept": "application/vnd.github.v3+json", - "Authorization": f"token {os.environ['GITHUB_TOKEN']}" + "Authorization": f"token {os.environ['GITHUB_TOKEN']}", + "Content-Type": mediatype }, params={ "name": artifact @@ -59,8 +59,13 @@ if __name__ == "__main__": body = release["body"] body = re.sub( - r"(https://lab\.flipper\.net/\?url=).*?(&channel=XFW-Updater&version=" + os.environ['VERSION_TAG'] + r")", - r"\1" + os.environ['ARTIFACT_WEB'] + r"\2", + r"(https://lab\.flipper\.net/\?url=).*?(&channel=XFW-Updater&version=)[A-Za-z0-9_-]+", + r"\1" + os.environ['ARTIFACT_WEB'] + r"\2" + os.environ['VERSION_TAG'], + body + ) + body = re.sub( + r"(https://github\.com/ClaraCrazy/Flipper-Xtreme/releases/download/[A-Za-z0-9_-]+?/)[A-Za-z0-9_-]+", + r"\1" + os.environ['VERSION_TAG'], body ) body = body.replace("", "") insert = body.find("\n [//]: \n") - body = body[:insert] + hotfix + body[:insert] + body = body[:insert] + hotfix + body[insert:] req = requests.patch( release["url"], From d2ca67d261217f445abaf9b3cb0926250d1385a9 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 4 May 2023 07:04:26 +0400 Subject: [PATCH 125/216] [FL-3242] SubGhz: refactoring app (#2554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add SubGhzThresholdRssi * SubGhz: remove direct reading of subghz-txrx-txrx_state * SubGhz: remove direct reading subghz->txrx->hopper_state * SubGhz: remove direct reading subghz->lock * SubGhz: check load type file * SubGhz: remove direct reading subghz->txrx->rx_key_state * SubGhz: remove direct reading subghz->txrx->speaker_state * SubGhz: refactoring subghz_scene_set_type.c * SubGhz: moving "txrx" entity to a separate file * SubGhz: show error tx start * SubGhz: refactoring RPC * SubGhz: value get optimizations * SubGhz: fix name file * SubGhz: add function description * SubGhz: fix double back with a blocked transmission in this region and speacker, when a transmission is blocked in this region * SubGhz: correct spelling * SubGhz: better naming * SubGhz: simplify includes Co-authored-by: SG Co-authored-by: あく --- .../views/weather_station_receiver.c | 6 +- .../main/subghz/helpers/subghz_custom_event.h | 5 +- .../subghz_frequency_analyzer_worker.c | 2 +- .../subghz/helpers/subghz_threshold_rssi.c | 60 ++ .../subghz/helpers/subghz_threshold_rssi.h | 43 ++ .../main/subghz/helpers/subghz_txrx.c | 521 ++++++++++++++++++ .../main/subghz/helpers/subghz_txrx.h | 290 ++++++++++ .../helpers/subghz_txrx_create_potocol_key.c | 164 ++++++ .../helpers/subghz_txrx_create_potocol_key.h | 96 ++++ .../main/subghz/helpers/subghz_txrx_i.h | 27 + .../main/subghz/helpers/subghz_types.h | 7 + .../main/subghz/scenes/subghz_scene_delete.c | 4 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_need_saving.c | 18 +- .../subghz/scenes/subghz_scene_read_raw.c | 229 +++----- .../subghz/scenes/subghz_scene_receiver.c | 120 ++-- .../scenes/subghz_scene_receiver_config.c | 133 +++-- .../scenes/subghz_scene_receiver_info.c | 112 ++-- .../subghz/scenes/subghz_scene_region_info.c | 3 +- .../main/subghz/scenes/subghz_scene_rpc.c | 20 +- .../subghz/scenes/subghz_scene_save_name.c | 16 +- .../subghz/scenes/subghz_scene_save_success.c | 4 +- .../main/subghz/scenes/subghz_scene_saved.c | 4 +- .../subghz/scenes/subghz_scene_set_type.c | 255 ++------- .../subghz/scenes/subghz_scene_show_error.c | 11 +- .../main/subghz/scenes/subghz_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 46 +- applications/main/subghz/subghz.c | 91 +-- applications/main/subghz/subghz_i.c | 401 +++----------- applications/main/subghz/subghz_i.h | 80 +-- applications/main/subghz/views/receiver.c | 23 +- applications/main/subghz/views/receiver.h | 2 +- .../main/subghz/views/subghz_read_raw.c | 8 +- .../main/subghz/views/subghz_read_raw.h | 2 +- applications/main/subghz/views/transmitter.c | 6 +- applications/main/subghz/views/transmitter.h | 2 +- lib/subghz/environment.c | 2 + 37 files changed, 1702 insertions(+), 1115 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.c create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.h create mode 100644 applications/main/subghz/helpers/subghz_txrx.c create mode 100644 applications/main/subghz/helpers/subghz_txrx.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_i.h diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index f8e2e3288..c4ce1627e 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 765c9e251..285b4a60f 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -6,14 +6,13 @@ typedef enum { SubGhzCustomEventManagerSetRAW, //SubmenuIndex - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + SubmenuIndexPricenton_315, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, SubmenuIndexCAMETwee, - SubmenuIndexNeroSketch, - SubmenuIndexNeroRadio, SubmenuIndexGateTX, SubmenuIndexDoorHan_315_00, SubmenuIndexDoorHan_433_92, diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 5d1a80a39..4a4445faa 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont instance->thread = furi_thread_alloc_ex( "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance); SubGhz* subghz = context; - instance->setting = subghz->setting; + instance->setting = subghz_txrx_get_setting(subghz->txrx); return instance; } diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c new file mode 100644 index 000000000..04a06bc17 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -0,0 +1,60 @@ +#include "subghz_threshold_rssi.h" +#include +#include "../subghz_i.h" + +#define TAG "SubGhzThresholdRssi" +#define THRESHOLD_RSSI_LOW_COUNT 10 + +struct SubGhzThresholdRssi { + float threshold_rssi; + uint8_t threshold_rssi_low_count; +}; + +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) { + SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi)); + instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + return instance; +} + +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) { + furi_assert(instance); + free(instance); +} + +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) { + furi_assert(instance); + instance->threshold_rssi = rssi; +} + +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { + furi_assert(instance); + return instance->threshold_rssi; +} + +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { + furi_assert(instance); + float rssi = furi_hal_subghz_get_rssi(); + SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; + + if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { + ret.is_above = true; + } else { + if(rssi < instance->threshold_rssi) { + instance->threshold_rssi_low_count++; + if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) { + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + } + ret.is_above = false; + } else { + instance->threshold_rssi_low_count = 0; + } + + if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) { + ret.is_above = false; + } else { + ret.is_above = true; + } + } + return ret; +} diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h new file mode 100644 index 000000000..e28092acb --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +typedef struct { + float rssi; /**< Current RSSI */ + bool is_above; /**< Exceeded threshold level */ +} SubGhzThresholdRssiData; + +typedef struct SubGhzThresholdRssi SubGhzThresholdRssi; + +/** Allocate SubGhzThresholdRssi + * + * @return SubGhzThresholdRssi* + */ +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void); + +/** Free SubGhzThresholdRssi + * + * @param instance Pointer to a SubGhzThresholdRssi + */ +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance); + +/** Set threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi RSSI threshold + */ +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi); + +/** Get threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return float RSSI threshold + */ +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); + +/** Check threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return SubGhzThresholdRssiData + */ +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c new file mode 100644 index 000000000..1517cb998 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -0,0 +1,521 @@ +#include "subghz_txrx_i.h" + +#include + +#define TAG "SubGhz" + +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); + + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); + + instance->txrx_state = SubGhzTxRxStateSleep; + + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); + + instance->environment = subghz_environment_alloc(); + instance->is_database_loaded = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + + subghz_worker_set_overrun_callback( + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); + + return instance; +} + +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); + + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); +} + +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->is_database_loaded; +} + +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; +} + +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + preset_name = "CUSTOM"; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + } + return preset_name; +} + +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; +} + +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation) { + furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); + } +} + +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_txrx_speaker_on(instance); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); + furi_hal_subghz_sleep(); + instance->txrx_state = SubGhzTxRxStateSleep; +} + +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(&gpio_cc1101_g0, false); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; + } + + return ret; +} + +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); + furi_assert(flipper_format); + + subghz_txrx_stop(instance); + + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + ret = SubGhzTxRxStartTxStateOk; + + SubGhzRadioPreset* preset = instance->preset; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); + + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + } else { + FURI_LOG_E( + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + if(ret == SubGhzTxRxStartTxStateOk) { + //Start TX + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + if(ret != SubGhzTxRxStartTxStateOk) { + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); +} + +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; +} + +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + + //if protocol dynamic then we save the last upload + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); + } + } + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->txrx_state) { + case SubGhzTxRxStateTx: + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + break; + case SubGhzTxRxStateRx: + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + break; + + default: + break; + } +} + +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + instance->hopper_state = SubGhzHopperStateRunnig; + } + // Select next frequency + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; + } else { + instance->hopper_idx_frequency = 0; + } + + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); + }; + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); + } +} + +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; +} + +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; +} + +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunnig; + } +} + +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunnig) { + instance->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } else { + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + furi_hal_speaker_release(); + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } +} + +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } +} + +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; +} + +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; +} + +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); + furi_assert(name_protocol); + bool res = false; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; +} + +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { + furi_assert(instance); + return ( + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; + if(check_type) { + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); +} + +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); +} + +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), + callback, + context); +} diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h new file mode 100644 index 000000000..0f2daf05d --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -0,0 +1,290 @@ +#pragma once + +#include "subghz_types.h" + +#include +#include +#include +#include +#include + +typedef struct SubGhzTxRx SubGhzTxRx; + +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + +typedef enum { + SubGhzTxRxStartTxStateOk, + SubGhzTxRxStartTxStateErrorOnlyRx, + SubGhzTxRxStartTxStateErrorParserOthers, +} SubGhzTxRxStartTxState; + +/** + * Allocate SubGhzTxRx + * + * @return SubGhzTxRx* pointer to SubGhzTxRx + */ +SubGhzTxRx* subghz_txrx_alloc(); + +/** + * Free SubGhzTxRx + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_free(SubGhzTxRx* instance); + +/** + * Check if the database is loaded + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if the database is loaded + */ +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance); + +/** + * Set preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + */ +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size); + +/** + * Get name of preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset String of preset + * @return const char* Name of preset + */ +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset); + +/** + * Get of preset + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzRadioPreset Preset + */ +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); + +/** + * Get string frequency and modulation + * + * @param instance Pointer to a SubGhzTxRx + * @param frequency Pointer to a string frequency + * @param modulation Pointer to a string modulation + */ +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation); + +/** + * Start TX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + * @param flipper_format Pointer to a FlipperFormat + * @return SubGhzTxRxStartTxState + */ +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); + +/** + * Start RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_rx_start(SubGhzTxRx* instance); + +/** + * Stop TX/RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_stop(SubGhzTxRx* instance); + +/** + * Set sleep mode CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_sleep(SubGhzTxRx* instance); + +/** + * Update frequency CC1101 in automatic mode (hopper) + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_update(SubGhzTxRx* instance); + +/** + * Get state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzHopperState + */ +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); + +/** + * Set state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @param state State hopper + */ +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); + +/** + * Unpause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance); + +/** + * Set pause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_pause(SubGhzTxRx* instance); + +/** + * Speaker on + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_on(SubGhzTxRx* instance); + +/** + * Speaker off + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_off(SubGhzTxRx* instance); + +/** + * Speaker mute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_mute(SubGhzTxRx* instance); + +/** + * Speaker unmute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); + +/** + * Set state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @param state State speaker + */ +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); + +/** + * Get state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSpeakerState + */ +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); + +/** + * load decoder by name protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_protocol Name protocol + * @return bool True if the decoder is loaded + */ +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); + +/** + * Get decoder + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase + */ +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); + +/** + * Set callback for save data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for save data + * @param context Context for callback + */ +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context); + +/** + * Get pointer to a load data key + * + * @param instance Pointer to a SubGhzTxRx + * @return FlipperFormat* + */ +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance); + +/** + * Get pointer to a SugGhzSetting + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSetting* + */ +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); + +/** + * Is it possible to save this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to save this protocol + */ +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance); + +/** + * Is it possible to send this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to send this protocol + */ +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type); + +/** + * Set filter, what types of decoder to use + * + * @param instance Pointer to a SubGhzTxRx + * @param filter Filter + */ +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); + +/** + * Set callback for receive data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for receive data + * @param context Context for callback + */ +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context); + +/** + * Set callback for Raw decoder, end of data transfer + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for Raw decoder, end of data transfer + * @param context Context for callback + */ +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context); diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c new file mode 100644 index 000000000..41e4f7c4e --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c @@ -0,0 +1,164 @@ +#include "subghz_txrx_i.h" +#include "subghz_txrx_create_potocol_key.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TAG "SubGhzCreateProtocolKey" + +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhzTxRx* instance = context; + + bool res = false; + + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); + + if(instance->decoder_result == NULL) { + //TODO: Error + // furi_string_set(error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); + FURI_LOG_E(TAG, "Protocol not found!"); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + instance->decoder_result, instance->fff_data, instance->preset) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(instance); + bool ret = false; + if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + furi_assert(instance); + + bool ret = false; + serial &= 0x0FFFFFFF; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + name_sysmem, + instance->preset); + ret = true; + } + subghz_transmitter_free(instance->transmitter); + return ret; +} + +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(instance); + + bool ret = false; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + instance->preset); + ret = true; + } + return ret; +} + +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency) { + furi_assert(instance); + + bool ret = false; + uint32_t serial = (uint32_t)rand(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = (uint32_t)rand(); + } + if(subghz_txrx_gen_data_protocol( + instance, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h new file mode 100644 index 000000000..5eed93034 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h @@ -0,0 +1,96 @@ +#pragma once +#include "subghz_types.h" +#include "subghz_txrx.h" + +/** + * Generate data for protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +/** + * Generate data for protocol and te + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @param te Te + * @return bool True if success + */ +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +/** + * Generate data Keeloq protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param name_sysmem Name of Keeloq sysmem + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + const char* name_sysmem, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +/** + * Generate data SecPlus v2 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +/** + * Generate data SecPlus v1 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @return bool True if success + */ +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h new file mode 100644 index 000000000..bd0ad8b7b --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -0,0 +1,27 @@ +#pragma once + +#include "subghz_txrx.h" + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool is_database_loaded; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; +}; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 2bd2f6820..46bf940f4 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -77,3 +77,10 @@ typedef enum { SubGhzViewIdTestCarrier, SubGhzViewIdTestPacket, } SubGhzViewId; + +/** SubGhz load type file */ +typedef enum { + SubGhzLoadTypeFileNoLoad, + SubGhzLoadTypeFileKey, + SubGhzLoadTypeFileRaw, +} SubGhzLoadTypeFile; diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b143..0d14cd23a 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) { modulation_str = furi_string_alloc(); text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f64..8dff442a8 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index e157246aa..f29f26309 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) { bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneStay) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.event == SubGhzCustomEventSceneExit) { - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + SubGhzRxKeyState state = subghz_rx_key_state_get(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + + if(state == SubGhzRxKeyStateExit) { + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_previous_scene(subghz->scene_manager); } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 09440b32b..6e576a861 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -3,11 +3,9 @@ #include #include #include -#include #define RAW_FILE_NAME "Raw_signal_" #define TAG "SubGhzSceneReadRAW" -#define RAW_THRESHOLD_RSSI_LOW_COUNT 10 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { FuriString* temp_str; temp_str = furi_string_alloc(); do { - if(!flipper_format_rewind(subghz->txrx->fff_data)) { + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); + if(!flipper_format_rewind(fff_data)) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) { + if(!flipper_format_read_string(fff_data, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_read_raw_add_data_statusbar( subghz->subghz_read_raw, furi_string_get_cstr(frequency_str), @@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); - switch(subghz->txrx->rx_key_state) { + float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi); + switch(subghz_rx_key_state_get(subghz)) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); + subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); @@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); @@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + threshold_rssi); break; default: subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusStart, - "", - subghz->txrx->raw_threshold_rssi); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi); break; } + + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + } furi_string_free(file_name); subghz_scene_read_raw_update_statusbar(subghz); //set callback view raw subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME)); //set filter RAW feed - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); + subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); } bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; + SubGhzProtocolDecoderRAW* decoder_raw = + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx); if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + + subghz_txrx_stop(subghz->txrx); //Stop save file - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? - if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || - (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || + (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { //Restore default setting - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_set_default_preset(subghz); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { if(!scene_manager_search_and_switch_to_previous_scene( @@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWTXRXStop: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWErase: - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { if(subghz_scene_read_raw_update_filename(subghz)) { furi_string_set(subghz->file_path_tmp, subghz->file_path); subghz_delete_file(subghz); } } - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); notification_message(subghz->notifications, &sequence_reset_rgb); consumed = true; break; @@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); consumed = true; } else { @@ -223,33 +194,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; - subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusIDLE, - "", - subghz->txrx->raw_threshold_rssi); - } else { - if(scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneSaved) || - !scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneStart)) { - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } - // set callback end tx - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - subghz->txrx->transmitter), - subghz_scene_read_raw_callback_end_tx, - subghz); - subghz->state_notifications = SubGhzNotificationStateTx; + if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz_threshold_rssi_get(subghz->threshold_rssi)); + } else { + if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) || + !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) { + DOLPHIN_DEED(DolphinDeedSubGhzSend); } + // set callback end tx + subghz_txrx_set_raw_file_encoder_worker_callback_end( + subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz); + subghz->state_notifications = SubGhzNotificationStateTx; } } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_speaker_unmute(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); subghz_read_raw_stop_send(subghz->subghz_read_raw); consumed = true; break; case SubGhzCustomEventViewReadRAWIDLE: - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); + size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw); - size_t spl_count = subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + subghz_protocol_raw_save_to_file_stop(decoder_raw); - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); furi_string_free(temp_str); if(spl_count > 0) { @@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); consumed = true; break; case SubGhzCustomEventViewReadRAWREC: - if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - if(subghz_protocol_raw_save_to_file_init( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, - RAW_FILE_NAME, - subghz->txrx->preset)) { + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_txrx_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { furi_string_set(subghz->error_str, "Function requires\nan SD card."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); @@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); + subghz_read_raw_update_sample_write( - subghz->subghz_read_raw, - subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); - - float rssi = furi_hal_subghz_get_rssi(); - - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - } else { - if(rssi < subghz->txrx->raw_threshold_rssi) { - subghz->txrx->raw_threshold_rssi_low_count++; - if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - } - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - } else { - subghz->txrx->raw_threshold_rssi_low_count = 0; - } - - if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); - subghz_speaker_mute(subghz); - } else { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - subghz_speaker_unmute(subghz); - } - } + subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); + SubGhzThresholdRssiData ret_rssi = + subghz_threshold_get_rssi_data(subghz->threshold_rssi); + subghz_read_raw_add_data_rssi( + subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); + subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); break; case SubGhzNotificationStateTx: notification_message(subghz->notifications, &sequence_blink_magenta_10); @@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) { SubGhz* subghz = context; //Stop CC1101 - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); //filter restoration - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 93c369092..dcc22b91c 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); - if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* history_stat_str = furi_string_alloc(); + if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) { + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, @@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + SubGhzHistory* history = subghz->history; + FuriString* str_buff = furi_string_alloc(); - if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + + if(subghz_history_add_to_history(history, decoder_base, &preset)) { furi_string_reset(str_buff); subghz->state_notifications = SubGhzNotificationStateRxDone; - - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + uint16_t item_history = subghz_history_get_item(history); + subghz_history_get_text_item_menu(history, str_buff, item_history - 1); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol( - subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + subghz_history_get_type_protocol(history, item_history - 1)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); furi_string_free(str_buff); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; + SubGhzHistory* history = subghz->history; FuriString* str_buff; str_buff = furi_string_alloc(); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - subghz_history_reset(subghz->txrx->history); - subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { + subghz_set_default_preset(subghz); + subghz_history_reset(history); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } - subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz)); //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(history); i++) { furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + subghz_history_get_text_item_menu(history, str_buff, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol(subghz->txrx->history, i)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_history_get_type_protocol(history, i)); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(str_buff); subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); - subghz_receiver_set_rx_callback( - subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz); subghz->state_notifications = SubGhzNotificationStateRx; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + subghz_txrx_rx_start(subghz->txrx); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check( + subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME)); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); } @@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->idx_menu_chosen = 0; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); + subghz_txrx_stop(subghz->txrx); + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz->idx_menu_chosen = 0; + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz_preset_init( - subghz, - "AM650", - subghz_setting_get_default_frequency(subghz->setting), - NULL, - 0); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz_set_default_preset(subghz); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } consumed = true; break; case SubGhzCustomEventViewReceiverOK: - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); consumed = true; break; @@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverUnlock: - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); consumed = true; break; default: break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); subghz_scene_receiver_update_statusbar(subghz); } - //get RSSI - float rssi = furi_hal_subghz_get_rssi(); - subghz_receiver_rssi(subghz->subghz_receiver, rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + + subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); + (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi); switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); break; case SubGhzNotificationStateRxDone: - if(subghz->lock != SubGhzLockOn) { + if(!subghz_is_locked(subghz)) { notification_message(subghz->notifications, &subghs_sequence_rx); } else { notification_message(subghz->notifications, &subghs_sequence_rx_locked); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 895e43342..55a8f6b44 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) { - if(value == subghz_setting_get_frequency(subghz->setting, i)) { + for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) { + if(value == subghz_setting_get_frequency(setting, i)) { index = i; break; } else { - index = subghz_setting_get_frequency_default_index(subghz->setting); + index = subghz_setting_get_frequency_default_index(setting); } } return index; @@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) { furi_assert(context); SubGhz* subghz = context; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) { + for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) { + if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz->setting); + // index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); } } return index; @@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, index); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); } else { variable_item_set_current_value_index( - item, subghz_setting_get_frequency_default_index(subghz->setting)); + item, subghz_setting_get_frequency_default_index(setting)); } } static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, index)); - subghz_preset_init( - subghz, - subghz_setting_get_preset_name(subghz->setting, index), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, index), - subghz_setting_get_preset_data_size(subghz->setting, index)); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index)); + + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + subghz_txrx_set_preset( + subghz->txrx, + subghz_setting_get_preset_name(setting, index), + preset.frequency, + subghz_setting_get_preset_data(setting, index), + subghz_setting_get_preset_data_size(setting, index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig); variable_item_set_current_value_text(item, hopping_text[index]); if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_default_frequency(setting); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting); + frequency / 1000000, + (frequency % 1000000) / 10000); + variable_item_set_current_value_text(frequency_item, text_buf); + + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + frequency, + preset.data, + preset.data_size); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } else { - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - " -----"); + variable_item_set_current_value_text(frequency_item, " -----"); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } - subghz->txrx->hopper_state = hopping_value[index]; + subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz->txrx->speaker_state = speaker_value[index]; + subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, bin_raw_text[index]); - subghz->txrx->filter = bin_raw_value[index]; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz->filter = bin_raw_value[index]; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { @@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; + subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]); } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz->setting), + subghz_setting_get_frequency_count(setting), subghz_scene_receiver_config_set_frequency, subghz); - value_index = - subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz); + value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); variable_item_set_current_value_index(item, value_index); char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, value_index); snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, value_index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != @@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } @@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) { item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz->setting), + subghz_setting_get_preset_count(setting), subghz_scene_receiver_config_set_preset, subghz); - value_index = subghz_scene_receiver_config_next_preset( - furi_string_get_cstr(subghz->txrx->preset->name), subghz); + value_index = + subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, value_index)); + item, subghz_setting_get_preset_name(setting, value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { @@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { BIN_RAW_COUNT, subghz_scene_receiver_config_set_bin_raw, subghz); - value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); + value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, bin_raw_text[value_index]); } @@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) { SPEAKER_COUNT, subghz_scene_receiver_config_set_speaker, subghz); - value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); + value_index = value_index_uint32( + subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); @@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz_threshold_rssi_get(subghz->threshold_rssi), + raw_theshold_rssi_value, + RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); } @@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneSettingLock) { - subghz->lock = SubGhzLockOn; + subghz_lock(subghz); scene_manager_previous_scene(subghz->scene_manager); consumed = true; } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 152334ad6..9b57165e7 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhz* subghz = context; - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, + subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, - subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz_txrx_get_decoder(subghz->txrx), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = - subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); - subghz_preset_init( - subghz, + subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); + subghz_txrx_set_preset( + subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, preset->data, @@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); widget_add_string_element( subghz->widget, 78, @@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); @@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { furi_string_free(modulation_str); furi_string_free(text); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { widget_add_button_element( subghz->widget, GuiButtonTypeRight, @@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { subghz_scene_receiver_info_callback, subghz); } - if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - subghz->txrx->decoder_result->protocol->encoder->deserialize && - subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) { + if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) { widget_add_button_element( subghz->widget, GuiButtonTypeCenter, @@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { - //CC1101 Stop RX -> Start TX - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz->txrx->hopper_state = SubGhzHopperStatePause; - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || - subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { - if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - subghz->state_notifications = SubGhzNotificationStateRx; - } else { - subghz->state_notifications = SubGhzNotificationStateTx; - } + //CC1101 Stop RX -> Start TX + subghz_txrx_hopper_pause(subghz->txrx); + if(!subghz_tx_start( + subghz, + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); + subghz->state_notifications = SubGhzNotificationStateRx; + } else { + subghz->state_notifications = SubGhzNotificationStateTx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } + + subghz_txrx_rx_start(subghz->txrx); + + subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - } + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + + subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_region_info.c b/applications/main/subghz/scenes/subghz_scene_region_info.c index 82486314d..b98394af0 100644 --- a/applications/main/subghz/scenes/subghz_scene_region_info.c +++ b/applications/main/subghz/scenes/subghz_scene_region_info.c @@ -5,8 +5,7 @@ void subghz_scene_region_info_on_enter(void* context) { SubGhz* subghz = context; const FuriHalRegion* const region = furi_hal_region_get(); - FuriString* buffer; - buffer = furi_string_alloc(); + FuriString* buffer = furi_string_alloc(); if(region) { furi_string_cat_printf(buffer, "Region: %s, bands:\n", region->country_code); for(uint16_t i = 0; i < region->bands_count; ++i) { diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index a1c0e41fd..aa6f132d7 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -3,6 +3,7 @@ typedef enum { SubGhzRpcStateIdle, SubGhzRpcStateLoaded, + SubGhzRpcStateTx, } SubGhzRpcState; void subghz_scene_rpc_on_enter(void* context) { @@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) && - (state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz->txrx->fff_data); + if((state == SubGhzRpcStateLoaded)) { + result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); + state = SubGhzRpcStateTx; if(result) subghz_blink_start(subghz); } if(!result) { @@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); + state = SubGhzRpcStateIdle; result = true; } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); @@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); + SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); + if(state != SubGhzRpcStateIdle) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 255ba228b..2a292a1ef 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( @@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( subghz, - subghz->txrx->fff_data, + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, @@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { } else { subghz_save_protocol_to_file( subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } @@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 2977975f7..40ade5a53 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(event.event == SubGhzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index 62ade3508..8b198e339 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) { SubGhz* subghz = context; if(subghz_load_protocol_from_file(subghz)) { - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 2134377e3..32e0d6588 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,63 +1,10 @@ #include "../subghz_i.h" -#include -#include -#include +#include "../helpers/subghz_txrx_create_potocol_key.h" #include -#include -#include #include #define TAG "SubGhzSetType" -bool subghz_scene_set_type_submenu_gen_data_protocol( - void* context, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t frequency, - const char* preset_name) { - furi_assert(context); - SubGhz* subghz = context; - - bool res = false; - - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); - - if(subghz->txrx->decoder_result == NULL) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) { submenu_add_item( subghz->submenu, "Princeton_433", - SubmenuIndexPricenton, + SubmenuIndexPricenton_433, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "Princeton_315", + SubmenuIndexPricenton_315, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexCAMETwee, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz); - // submenu_add_item( - // subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( subghz->submenu, "Gate TX_433", @@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { - //ToDo Fix - uint32_t key = subghz_random_serial(); + uint32_t key = (uint32_t)rand(); switch(event.event) { - case SubmenuIndexPricenton: + case SubmenuIndexPricenton_433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) { - uint32_t te = 400; - flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); + break; + case SubmenuIndexPricenton_315: + key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) { - generated_protocol = true; - } + + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; - // case SubmenuIndexNeroSketch: - // /* code */ - // break; - // case SubmenuIndexNeroRadio: - // /* code */ - // break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexDoorHan_433_92: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key & 0x0FFFFFFF, - 0x2, - 0x0003, - "DoorHan", - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_keelog_protocol( + subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 315000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 390000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexSecPlus_v2_310_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 310000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 390000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000); break; default: return false; diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index eadfb2114..d52eca9b6 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index a50f73a81..a41e4b06f 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 712e50071..1c193c179 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; - if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + if(decoder) { + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); if(subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); + decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { + subghz_protocol_decoder_base_get_string(decoder, key_str); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) { - show_button = 1; - } - - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), - show_button); + subghz_txrx_protocol_is_transmittable(subghz->txrx, false)); ret = true; } furi_string_free(frequency_str); @@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->state_notifications = SubGhzNotificationStateTx; - subghz_scene_transmitter_update_data_show(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } + + if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { + subghz->state_notifications = SubGhzNotificationStateTx; + subghz_scene_transmitter_update_data_show(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzSend); } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz->txrx); return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 25233fe21..09963584a 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -1,9 +1,6 @@ /* Abandon hope, all ye who enter here. */ -#include "subghz/types.h" #include "subghz_i.h" -#include -#include bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) } } -void subghz_blink_start(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_start_magenta); -} - -void subghz_blink_stop(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_stop); -} - SubGhz* subghz_alloc() { SubGhz* subghz = malloc(sizeof(SubGhz)); @@ -163,45 +150,18 @@ SubGhz* subghz_alloc() { SubGhzViewIdStatic, subghz_test_static_get_view(subghz->subghz_test_static)); - //init setting - subghz->setting = subghz_setting_alloc(); - subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user")); + //init threshold rssi + subghz->threshold_rssi = subghz_threshold_rssi_alloc(); - //init Worker & Protocol & History & KeyBoard - subghz->lock = SubGhzLockOff; - subghz->txrx = malloc(sizeof(SubGhzTxRx)); - subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); - subghz->txrx->preset->name = furi_string_alloc(); - subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + subghz_unlock(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz->history = subghz_history_alloc(); + subghz->filter = SubGhzProtocolFlag_Decodable; - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; - subghz->txrx->history = subghz_history_alloc(); - subghz->txrx->worker = subghz_worker_alloc(); - subghz->txrx->fff_data = flipper_format_string_alloc(); - - subghz->txrx->environment = subghz_environment_alloc(); - subghz_environment_set_came_atomo_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry( - subghz->txrx->environment, (void*)&subghz_protocol_registry); - subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); - subghz->txrx->filter = SubGhzProtocolFlag_Decodable; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); - - subghz_worker_set_overrun_callback( - subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); - subghz_worker_set_pair_callback( - subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); + //init TxRx & History & KeyBoard + subghz->txrx = subghz_txrx_alloc(); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); + subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz); //Init Error_str subghz->error_str = furi_string_alloc(); @@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) { subghz->rpc_ctx = NULL; } - subghz_speaker_off(subghz); + subghz_txrx_speaker_off(subghz->txrx); + subghz_txrx_stop(subghz->txrx); + subghz_txrx_sleep(subghz->txrx); // Packet Test view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); @@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - //setting - subghz_setting_free(subghz->setting); + // threshold rssi + subghz_threshold_rssi_free(subghz->threshold_rssi); //Worker & Protocol & History - subghz_receiver_free(subghz->txrx->receiver); - subghz_environment_free(subghz->txrx->environment); - subghz_worker_free(subghz->txrx->worker); - flipper_format_free(subghz->txrx->fff_data); - subghz_history_free(subghz->txrx->history); - furi_string_free(subghz->txrx->preset->name); - free(subghz->txrx->preset); - free(subghz->txrx); + subghz_history_free(subghz->history); + + //TxRx + subghz_txrx_free(subghz->txrx); //Error string furi_string_free(subghz->error_str); @@ -319,11 +277,6 @@ int32_t subghz_app(void* p) { return 1; } - //Load database - bool load_database = subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); // Check argument and run corresponding scene if(p && strlen(p)) { uint32_t rpc_ctx = 0; @@ -340,9 +293,9 @@ int32_t subghz_app(void* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX @@ -358,7 +311,7 @@ int32_t subghz_app(void* p) { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); - if(load_database) { + if(subghz_txrx_is_database_loaded(subghz->txrx)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } else { scene_manager_set_scene_state( diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 18d87c76b..8036ed5f7 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,214 +18,42 @@ #define TAG "SubGhz" -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size) { - furi_assert(context); - SubGhz* subghz = context; - furi_string_set(subghz->txrx->preset->name, preset_name); - subghz->txrx->preset->frequency = frequency; - subghz->txrx->preset->data = preset_data; - subghz->txrx->preset->data_size = preset_data_size; -} - -bool subghz_set_preset(SubGhz* subghz, const char* preset) { - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - furi_string_set(subghz->txrx->preset->name, "AM270"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - furi_string_set(subghz->txrx->preset->name, "AM650"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - furi_string_set(subghz->txrx->preset->name, "FM238"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - furi_string_set(subghz->txrx->preset->name, "FM476"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - furi_string_set(subghz->txrx->preset->name, "CUSTOM"); - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - return true; -} - -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) { +void subghz_set_default_preset(SubGhz* subghz) { furi_assert(subghz); - if(frequency != NULL) { - furi_string_printf( - frequency, - "%03ld.%02ld", - subghz->txrx->preset->frequency / 1000000 % 1000, - subghz->txrx->preset->frequency / 10000 % 100); - } - if(modulation != NULL) { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name)); - } + subghz_txrx_set_preset( + subghz->txrx, + "AM650", + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + NULL, + 0); } -void subghz_begin(SubGhz* subghz, uint8_t* preset_data) { +void subghz_blink_start(SubGhz* subghz) { furi_assert(subghz); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; + notification_message(subghz->notifications, &sequence_blink_stop); + notification_message(subghz->notifications, &sequence_blink_start_magenta); } -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { +void subghz_blink_stop(SubGhz* subghz) { furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } - furi_assert( - subghz->txrx->txrx_state != SubGhzTxRxStateRx && - subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); - subghz_speaker_on(subghz); - furi_hal_subghz_rx(); - - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); - subghz_worker_start(subghz->txrx->worker); - subghz->txrx->txrx_state = SubGhzTxRxStateRx; - return value; -} - -static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { - furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); - if(ret) { - subghz_speaker_on(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateTx; - } - return ret; -} - -void subghz_idle(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_rx_end(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); - - if(subghz_worker_is_running(subghz->txrx->worker)) { - subghz_worker_stop(subghz->txrx->worker); - furi_hal_subghz_stop_async_rx(); - } - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_sleep(SubGhz* subghz) { - furi_assert(subghz); - furi_hal_subghz_sleep(); - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; + notification_message(subghz->notifications, &sequence_blink_stop); } bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { - furi_assert(subghz); + switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) { + case SubGhzTxRxStartTxStateErrorParserOthers: + dialog_message_show_storage_error( + subghz->dialogs, "Error in protocol\nparameters\ndescription"); + break; + case SubGhzTxRxStartTxStateErrorOnlyRx: + subghz_dialog_message_show_only_rx(subghz); + break; - bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - uint32_t repeat = 200; - do { - if(!flipper_format_rewind(flipper_format)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, furi_string_get_cstr(temp_str)); - - if(subghz->txrx->transmitter) { - if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) == - SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - } else { - FURI_LOG_E( - TAG, - "Unknown name preset \" %s \"", - furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_begin( - subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650")); - } - if(subghz->txrx->preset->frequency) { - ret = subghz_tx(subghz, subghz->txrx->preset->frequency); - } else { - ret = subghz_tx(subghz, 433920000); - } - if(ret) { - //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, subghz->txrx->transmitter); - } else { - subghz_dialog_message_show_only_rx(subghz); - } - } else { - dialog_message_show_storage_error( - subghz->dialogs, "Error in protocol\nparameters\ndescription"); - } - } - if(!ret) { - subghz_transmitter_free(subghz->txrx->transmitter); - if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) { - subghz_idle(subghz); - } - } - - } while(false); - furi_string_free(temp_str); - return ret; -} - -void subghz_tx_stop(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx); - //Stop TX - furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(subghz->txrx->transmitter); - subghz_transmitter_free(subghz->txrx->transmitter); - - //if protocol dynamic then we save the last upload - if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && - (subghz_path_is_file(subghz->file_path))) { - subghz_save_protocol_to_file( - subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + default: + return true; + break; } - subghz_idle(subghz); - subghz_speaker_off(subghz); - notification_message(subghz->notifications, &sequence_reset_red); + return false; } void subghz_dialog_message_show_only_rx(SubGhz* subghz) { @@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + Stream* fff_data_stream = + flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx)); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } + //Load frequency if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_E(TAG, "Missing Frequency"); break; @@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - subghz->txrx->preset->frequency = temp_data32; - + //Load preset if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; } - if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) { + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { break; } + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); - if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { //Todo add Custom_preset_module //delete preset if it already exists - subghz_setting_delete_custom_preset( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str)); //load custom preset from file if(!subghz_setting_load_custom_preset( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name), - fff_data_file)) { + setting, furi_string_get_cstr(temp_str), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); break; } } - size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_preset_init( - subghz, - furi_string_get_cstr(subghz->txrx->preset->name), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, preset_index), - subghz_setting_get_preset_data_size(subghz->setting, preset_index)); + size_t preset_index = + subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + subghz_txrx_set_preset( + subghz->txrx, + furi_string_get_cstr(temp_str), + temp_data32, + subghz_setting_get_preset_data(setting, preset_index), + subghz_setting_get_preset_data_size(setting, preset_index)); + //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; } + + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); + subghz->load_type_file = SubGhzLoadTypeFileRaw; + subghz_protocol_raw_gen_fff_data(fff_data, file_path); } else { + subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(subghz->txrx->fff_data)); + flipper_format_get_raw_stream(fff_data)); } - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, furi_string_get_cstr(temp_str)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, furi_string_get_cstr(temp_str))) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data); + subghz_txrx_get_decoder(subghz->txrx), fff_data); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; @@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } } +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) { + furi_assert(subghz); + return subghz->load_type_file; +} + bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file( return saved; } +void subghz_save_to_file(void* context) { + furi_assert(context); + SubGhz* subghz = context; + if(subghz_path_is_file(subghz->file_path)) { + subghz_save_protocol_to_file( + subghz, + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); + } +} + bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); @@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) { return furi_string_end_with(path, SUBGHZ_APP_EXTENSION); } -uint32_t subghz_random_serial(void) { - return (uint32_t)rand(); -} - -void subghz_hopper_update(SubGhz* subghz) { +void subghz_lock(SubGhz* subghz) { furi_assert(subghz); - - switch(subghz->txrx->hopper_state) { - case SubGhzHopperStateOFF: - case SubGhzHopperStatePause: - return; - case SubGhzHopperStateRSSITimeOut: - if(subghz->txrx->hopper_timeout != 0) { - subghz->txrx->hopper_timeout--; - return; - } - break; - default: - break; - } - float rssi = -127.0f; - if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { - // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); - - // Stay if RSSI is high enough - if(rssi > -90.0f) { - subghz->txrx->hopper_timeout = 10; - subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut; - return; - } - } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; - } - // Select next frequency - if(subghz->txrx->hopper_idx_frequency < - subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) { - subghz->txrx->hopper_idx_frequency++; - } else { - subghz->txrx->hopper_idx_frequency = 0; - } - - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_receiver_reset(subghz->txrx->receiver); - subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency( - subghz->setting, subghz->txrx->hopper_idx_frequency); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz->lock = SubGhzLockOn; } -void subghz_speaker_on(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } else { - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +void subghz_unlock(SubGhz* subghz) { + furi_assert(subghz); + subghz->lock = SubGhzLockOff; } -void subghz_speaker_off(SubGhz* subghz) { - if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - furi_hal_speaker_release(); - if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } +bool subghz_is_locked(SubGhz* subghz) { + furi_assert(subghz); + return (subghz->lock == SubGhzLockOn); } -void subghz_speaker_mute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - } +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) { + furi_assert(subghz); + subghz->rx_key_state = state; } -void subghz_speaker_unmute(SubGhz* subghz) { - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } - } +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { + furi_assert(subghz); + return subghz->rx_key_state; } diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 65480c6fd..fc3404c07 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -25,10 +25,6 @@ #include #include -#include -#include -#include -#include #include "subghz_history.h" @@ -37,34 +33,12 @@ #include "rpc/rpc_app.h" +#include "helpers/subghz_threshold_rssi.h" + +#include "helpers/subghz_txrx.h" + #define SUBGHZ_MAX_LEN_NAME 64 -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolFlag filter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - - SubGhzRadioPreset* preset; - SubGhzHistory* history; - uint16_t idx_menu_chosen; - SubGhzTxRxState txrx_state; - SubGhzHopperState hopper_state; - SubGhzSpeakerState speaker_state; - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - SubGhzRxKeyState rx_key_state; - - float raw_threshold_rssi; - uint8_t raw_threshold_rssi_low_count; -}; - -typedef struct SubGhzTxRx SubGhzTxRx; - struct SubGhz { Gui* gui; NotificationApp* notifications; @@ -93,47 +67,43 @@ struct SubGhz { SubGhzTestStatic* subghz_test_static; SubGhzTestCarrier* subghz_test_carrier; SubGhzTestPacket* subghz_test_packet; - FuriString* error_str; - SubGhzSetting* setting; - SubGhzLock lock; + SubGhzProtocolFlag filter; + FuriString* error_str; + SubGhzLock lock; + SubGhzThresholdRssi* threshold_rssi; + SubGhzRxKeyState rx_key_state; + SubGhzHistory* history; + uint16_t idx_menu_chosen; + SubGhzLoadTypeFile load_type_file; void* rpc_ctx; }; -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size); -bool subghz_set_preset(SubGhz* subghz, const char* preset); -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation); -void subghz_begin(SubGhz* subghz, uint8_t* preset_data); -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); -void subghz_rx_end(SubGhz* subghz); -void subghz_sleep(SubGhz* subghz); - -void subghz_blink_start(SubGhz* instance); -void subghz_blink_stop(SubGhz* instance); +void subghz_set_default_preset(SubGhz* subghz); +void subghz_blink_start(SubGhz* subghz); +void subghz_blink_stop(SubGhz* subghz); bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); -void subghz_tx_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); + bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, const char* dev_file_name); +void subghz_save_to_file(void* context); bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path); -uint32_t subghz_random_serial(void); -void subghz_hopper_update(SubGhz* subghz); -void subghz_speaker_on(SubGhz* subghz); -void subghz_speaker_off(SubGhz* subghz); -void subghz_speaker_mute(SubGhz* subghz); -void subghz_speaker_unmute(SubGhz* subghz); +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); + +void subghz_lock(SubGhz* subghz); +void subghz_unlock(SubGhz* subghz); +bool subghz_is_locked(SubGhz* subghz); + +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index acc39e258..f84ddfed0 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -44,7 +44,7 @@ typedef enum { } SubGhzViewReceiverBarShow; struct SubGhzViewReceiver { - SubGhzLock lock; + bool lock; uint8_t lock_count; FuriTimer* timer; View* view; @@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { instance->view, SubGhzViewReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); } -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; - if(lock == SubGhzLockOn) { - subghz_receiver->lock = lock; + + if(lock == true) { + subghz_receiver->lock = true; with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); } else { - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); } subghz_receiver->lock_count = 0; @@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; - if(subghz_receiver->lock == SubGhzLockOn) { + if(subghz_receiver->lock == true) { with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, true); - //subghz_receiver->lock = SubGhzLockOff; + //subghz_receiver->lock = false; furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); } @@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { // View allocation and configuration subghz_receiver->view = view_alloc(); - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->lock_count = 0; view_allocate_model( subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel)); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 9b12ccfee..5119105e9 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard); void subghz_view_receiver_set_callback( SubGhzViewReceiver* subghz_receiver, diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 87c8a3082..2ff598b60 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); } with_view_model( @@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod uint8_t x = 118; uint8_t y = 48; - if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) { uint8_t x = 118; - y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); uint8_t width = 3; for(uint8_t i = 0; i < x; i += width * 2) { diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index bc8711923..31aa9db6f 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,7 +3,7 @@ #include #include "../helpers/subghz_custom_event.h" -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct SubGhzReadRAW SubGhzReadRAW; diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 4a13460a3..86dc17a38 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -14,7 +14,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -104,7 +104,7 @@ 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); - model->show_button = 0; + model->show_button = false; }, false); return false; diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1af..06aae7c6b 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index b39b259d4..5ded243c4 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; return instance; } @@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; subghz_keystore_free(instance->keystore); free(instance); From a7d1ec03e878c062ba07132474720d0d54d26b97 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 126/216] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/gui/modules/menu.c | 2 + applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 583 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 14 files changed, 630 insertions(+), 418 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index 89e129ace..bf17a94e2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 0f042f6c4..3f94deebc 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -220,11 +220,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 4d1fa4950..053ac56f1 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -106,10 +106,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index 3e3b6c2e4..afae8b8fa 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -154,6 +154,8 @@ Menu* menu_alloc() { void menu_free(Menu* menu) { furi_assert(menu); menu_reset(menu); + with_view_model( + menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false); view_free(menu->view); free(menu); } diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c4148..f4d006e07 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63..be16e5091 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include -#define TAG "LoaderSrv" +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; -static Loader* loader_instance = NULL; - -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; - - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } - - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); - - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } - - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); - - furi_thread_start(loader_instance->application_thread); - - return true; + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - furi_assert(application->app); - furi_assert(application->name); +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} + +// callbacks + +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); +} + +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); + + Loader* loader = context; + LoaderEvent event; + + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); } - - loader_start_application(application, NULL); } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); + + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); } - FuriString* application_name; - application_name = furi_string_alloc(); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } - - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); - - furi_string_free(application_name); -} - -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); - } -} - -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + furi_thread_disable_heap_trace(loader->app.thread); + } + + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; + } else { + loader->app.insomniac = false; + } + + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); + + // start app thread + furi_thread_start(loader->app.thread); +} + +// process messages + +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } } -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; - - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; + } } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; +} - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; - } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { return LoaderStatusErrorAppStarted; } - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; + const FlipperApplication* app = loader_find_application_by_name(name); + + if(!app) { + return LoaderStatusErrorUnknownApp; } + loader_start_internal_app(loader, app, args); return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; - } - FURI_CRITICAL_EXIT(); - return result; -} - -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); -} - -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); - } -} - -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} - -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; -} - -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); - - free(instance); - instance = NULL; + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; +} + +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } + + free(loader->app.name); + loader->app.name = NULL; + + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} - -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); -} +// app int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -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 8dbc4fc35..e3a691b76 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_show_menu(); - -/** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 000000000..2d4602215 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b..2e3f10dad 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include - -#include -#include - -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 000000000..ec853661f --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 000000000..7405b87be --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 597710a53..dd3c0dc6b 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e..bc6844d35 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,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c176b2d7e..1c8424fe8 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1795,12 +1795,11 @@ 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,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From ac05387803b7f0c71594959b1c060fb765a58d29 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 3 May 2023 20:48:13 -0700 Subject: [PATCH 127/216] [FL-3270] Loader refactoring, part 1 (#2593) * Loader: menu part * Settings: remove unused loader api * Desktop: get loader from record_open * CLI: remove unneeded loader api * gitignore: ignore .old files * Loader: now really a service * Loader: working service prototype * Loader: cli, system start hooks * CI/CD: make happy * Loader: autorun * Loader: lock and unlock * Loader: rearrange code * Gui, module menu: fix memleak * Updater test: add timeout * added update timeouts and max run duration * Github: revert updater test workflow changes * Loader: less missleading message in info cli command Co-authored-by: doomwastaken Co-authored-by: Aleksandr Kutuzov --- .gitignore | 1 + applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 583 +++++++----------- applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 ++++ applications/services/loader/loader_i.h | 79 ++- applications/services/loader/loader_menu.c | 187 ++++++ applications/services/loader/loader_menu.h | 30 + .../settings/system/system_settings.c | 3 - firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- 13 files changed, 628 insertions(+), 418 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index eacfec1e4..f199a48be 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 4e3e1104a..a6b23c942 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -230,11 +230,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index fd04ff917..9109ef309 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -90,10 +90,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c4148..f4d006e07 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f83d47d63..be16e5091 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,76 +1,114 @@ -#include "applications.h" -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" +#include "loader_menu.h" +#include +#include -#define TAG "LoaderSrv" +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; -static Loader* loader_instance = NULL; - -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - loader_instance->application = application; - - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - } - - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); - - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } - - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); - - furi_thread_start(loader_instance->application_thread); - - return true; + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} - furi_assert(application->app); - furi_assert(application->name); +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} + +// callbacks + +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +static void loader_menu_click_callback(const char* name, void* context) { + Loader* loader = context; + loader_start(loader, name, NULL); +} + +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); + + Loader* loader = context; + LoaderEvent event; + + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); } - - loader_start_application(application, NULL); } -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} +// implementation -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; } static FlipperApplication const* loader_find_application_by_name_in_list( @@ -85,7 +123,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -100,346 +138,167 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); + + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); } - FuriString* application_name; - application_name = furi_string_alloc(); + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } - - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); - - furi_string_free(application_name); -} - -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); - } -} - -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + furi_thread_disable_heap_trace(loader->app.thread); + } + + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; + } else { + loader->app.insomniac = false; + } + + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); + + // start app thread + furi_thread_start(loader->app.thread); +} + +// process messages + +static void loader_do_menu_show(Loader* loader) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu); } } -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; - - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; + } } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; +} - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; - } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { return LoaderStatusErrorAppStarted; } - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; + const FlipperApplication* app = loader_find_application_by_name(name); + + if(!app) { + return LoaderStatusErrorUnknownApp; } + loader_start_internal_app(loader, app, args); return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; - } - FURI_CRITICAL_EXIT(); - return result; -} - -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); -} - -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); - } -} - -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} - -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; -} - -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { + return false; } - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); - - free(instance); - instance = NULL; + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; + return true; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; +} + +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); -} -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } + + free(loader->app.name); + loader->app.name = NULL; + + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} - -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); -} +// app int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; -} - -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 8dbc4fc35..e3a691b76 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -43,17 +41,14 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_show_menu(); - -/** Show primary loader */ -void loader_update_menu(); +void loader_show_menu(Loader* instance); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 000000000..2d4602215 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b..2e3f10dad 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,56 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include - -#include -#include - -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 000000000..ec853661f --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback(settings_view, loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 000000000..7405b87be --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, void*), + void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 8cbe62da8..5ab9cc6f0 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { @@ -137,8 +136,6 @@ static void hand_orient_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); } - - loader_update_menu(); } const char* const sleep_method[] = { diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f84bf074e..bc6844d35 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,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1375,12 +1375,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9c0cca01a..a4d1b87a6 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.3,, +Version,+,24.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1839,12 +1839,11 @@ 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,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* From 1f0c2c12666df847586cd347580930964ace0f46 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 02:09:21 +0300 Subject: [PATCH 128/216] SubGhz refactor merge pt 0 --- .../pocsag_pager/views/pocsag_pager_receiver.c | 6 +++--- .../weather_station/views/weather_station_receiver.c | 6 +++--- .../main/subghz/scenes/subghz_scene_show_error.c | 11 +++++------ .../main/subghz/scenes/subghz_scene_transmitter.c | 4 ++-- applications/main/subghz/views/transmitter.c | 6 +++--- applications/main/subghz/views/transmitter.h | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c index 532f41984..64939a956 100644 --- a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -69,10 +69,10 @@ void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { instance->view, PCSGReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index 62f1adad0..e994e7830 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index 107189cae..4544260ef 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ab9155fb7..f20d039cb 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -23,7 +23,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { key_str = furi_string_alloc(); frequency_str = furi_string_alloc(); modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + bool show_button = false; if(subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { @@ -31,7 +31,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { - show_button = 1; + show_button = true; } subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 2bec77690..5ae1a6e2c 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -16,7 +16,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; FuriString* temp_button_id; bool draw_temp_button; } SubGhzViewTransmitterModel; @@ -36,7 +36,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -119,7 +119,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->preset_str); furi_string_reset(model->key_str); furi_string_reset(model->temp_button_id); - model->show_button = 0; + model->show_button = false; model->draw_temp_button = false; }, false); diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 64bcbd1af..06aae7c6b 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); From c36b788b2db733bfa96c3b2bdbad347feb90f81f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:17:53 +0300 Subject: [PATCH 129/216] Use COUNT_OF in mouse jiggler --- applications/external/hid_app/views/hid_mouse_jiggler.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index 120d5bc34..09c14c668 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -6,8 +6,6 @@ #define TAG "HidMouseJiggler" -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - struct HidMouseJiggler { View* view; Hid* hid; @@ -44,7 +42,7 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); canvas_set_font(canvas, FontSecondary); if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); @@ -116,7 +114,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { consumed = true; } if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx < (int)COUNT_OF(intervals) - 1) { model->interval_idx++; consumed = true; } From b0b9e507e7b794e769866432cc07b1aa3faeeb42 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 03:51:16 +0300 Subject: [PATCH 130/216] SubGHz combine FuriString allocs --- .../subghz/scenes/subghz_scene_decode_raw.c | 28 +++++---------- .../main/subghz/scenes/subghz_scene_delete.c | 10 ++---- .../subghz/scenes/subghz_scene_delete_raw.c | 7 ++-- .../subghz/scenes/subghz_scene_read_raw.c | 16 +++------ .../subghz/scenes/subghz_scene_receiver.c | 24 +++++-------- .../scenes/subghz_scene_receiver_info.c | 10 ++---- .../main/subghz/scenes/subghz_scene_rpc.c | 3 +- .../subghz/scenes/subghz_scene_save_name.c | 8 ++--- .../subghz/scenes/subghz_scene_transmitter.c | 9 ++--- applications/main/subghz/subghz_cli.c | 36 +++++++------------ applications/main/subghz/subghz_history.c | 3 +- applications/main/subghz/subghz_i.c | 22 ++++-------- applications/main/subghz/views/receiver.c | 3 +- 13 files changed, 59 insertions(+), 120 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ac4fcccd..b9f2d236b 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -24,14 +24,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -62,11 +58,9 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -90,8 +84,7 @@ static void subghz_scene_add_to_history_callback( } bool subghz_scene_decode_raw_start(SubGhz* subghz) { - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); bool success = false; do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { @@ -148,8 +141,7 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { } // Update progress info - FuriString* progress_str; - progress_str = furi_string_alloc(); + FuriString* progress_str = furi_string_alloc(); subghz_file_encoder_worker_get_text_progress( subghz->decode_raw_file_worker_encoder, progress_str); @@ -164,10 +156,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b143..4cad14bbf 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -11,13 +11,9 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co void subghz_scene_delete_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f64..ee7983dfd 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -15,11 +15,8 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; FuriString* file_name; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 0c692e000..6a881cba4 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -12,8 +12,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; //set the path to read the file - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { FURI_LOG_E(TAG, "Rewind error"); @@ -38,11 +37,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz, frequency_str, NULL); @@ -74,8 +70,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: @@ -293,8 +288,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index b17a0700b..fd8d9b70e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -39,14 +39,10 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { @@ -90,12 +86,12 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); + SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -122,10 +118,8 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 58e428785..a108132c0 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -49,13 +49,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 9172f67c2..8140f69a2 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -72,8 +72,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); furi_string_set(subghz->file_path, arg); result = true; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); path_extract_filename(subghz->file_path, file_name, true); snprintf( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d3f5474be..2bb13f184 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -51,10 +51,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -109,7 +107,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index f20d039cb..d1fafd8ff 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -16,13 +16,10 @@ bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); bool show_button = false; if(subghz_protocol_decoder_base_deserialize( diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index c047a32b3..f30578fb2 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -215,8 +215,7 @@ static void subghz_cli_command_rx_callback( SubGhzCliCommandRx* instance = context; instance->packet_count++; - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_protocol_decoder_base_get_string(decoder_base, text); subghz_receiver_reset(receiver); printf("%s", furi_string_get_cstr(text)); @@ -384,14 +383,12 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { } void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); furi_string_set(file_name, ANY_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool check_file = false; @@ -526,10 +523,8 @@ static void subghz_cli_command_encrypt_keeloq(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); SubGhzKeystore* keystore = subghz_keystore_alloc(); @@ -569,10 +564,8 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); do { if(!args_read_string_and_trim(args, source)) { @@ -645,14 +638,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { size_t message_max_len = 64; uint8_t message[64] = {0}; - FuriString* input; - input = furi_string_alloc(); - FuriString* name; - name = furi_string_alloc(); - FuriString* output; - output = furi_string_alloc(); - FuriString* sysmsg; - sysmsg = furi_string_alloc(); + FuriString* input = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + FuriString* output = furi_string_alloc(); + FuriString* sysmsg = furi_string_alloc(); bool exit = false; SubGhzChatEvent chat_event; @@ -785,8 +774,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { - FuriString* cmd; - cmd = furi_string_alloc(); + FuriString* cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 3c018ec8b..396e28421 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -197,8 +197,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); item->preset = malloc(sizeof(SubGhzRadioPreset)); item->type = decoder_base->protocol->type; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index dd0160213..77eba42fb 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -145,8 +145,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { furi_assert(subghz); bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { @@ -254,8 +253,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -393,13 +391,9 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -446,8 +440,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -478,8 +471,7 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index d48ff8b96..811a46698 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -239,8 +239,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } bool scrollbar = model->history_item > 4; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* str_buff = furi_string_alloc(); SubGhzReceiverMenuItem* item_menu; From 914129a0d90a75952662f4c717d1d98ffe90fccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 5 May 2023 21:40:55 +0900 Subject: [PATCH 131/216] [FL-3289] Various Furi/FuriHal bug fixes and improvements (#2637) * Furi: properly handle thread free before TCB scrapping, add furi_free - more invasive version of free to memmgr. FuriHal: add DWT comparator api to cortex. Updater, RPC: refactor various thread shanenigans. Code cleanup. * Rollback free macros and related changes --- applications/services/loader/loader.c | 1 + applications/services/rpc/rpc.c | 50 +++++++------ .../services/storage/storage_external_api.c | 1 + .../services/storage/storages/storage_ext.c | 1 + .../power_settings_app/views/battery_info.c | 4 +- applications/system/updater/cli/updater_cli.c | 26 ++----- .../updater/util/update_task_worker_flasher.c | 6 +- firmware/targets/f18/api_symbols.csv | 7 +- firmware/targets/f7/api_symbols.csv | 7 +- .../targets/f7/furi_hal/furi_hal_cortex.c | 72 ++++++++++++++++++- .../furi_hal_include/furi_hal_cortex.h | 47 ++++++++++++ furi/core/thread.c | 30 ++++---- furi/core/thread.h | 8 +-- furi/core/timer.c | 10 +++ furi/core/timer.h | 4 ++ 15 files changed, 204 insertions(+), 70 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index be16e5091..f385efdf9 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -248,6 +248,7 @@ static void loader_do_app_closed(Loader* loader) { free(loader->app.name); loader->app.name = NULL; + furi_thread_join(loader->app.thread); furi_thread_free(loader->app.thread); loader->app.thread = NULL; } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 5b09e9b51..a759a12a9 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); RpcSession* session = (RpcSession*)context; + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); + } + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); + + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} + +static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { if(thread_state == FuriThreadStateStopped) { - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - rpc_systems[i].free(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); - } - furi_mutex_release(session->callbacks_mutex); - - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(session->thread); - free(session); + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); - furi_thread_set_state_callback(session->thread, rpc_session_free_callback); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); furi_thread_start(session->thread); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ffc3da4bc..bf474bc9d 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -803,6 +803,7 @@ void storage_file_free(File* file) { } FuriPubSub* storage_get_pubsub(Storage* storage) { + furi_assert(storage); return storage->pubsub; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index d802d6e9f..15a355dc2 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { file->internal_error_id = f_close(file_data); file->error_id = storage_ext_parse_error(file->internal_error_id); free(file_data); + storage_set_storage_file_data(file, NULL, storage); return (file->error_id == FSE_OK); } diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 0956cae4f..d56dfc628 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf( emote, sizeof(emote), diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 2bf6dab26..659c431f7 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { updater_cli_help(args); } -static int32_t updater_spawner_thread_worker(void* arg) { +static void updater_start_app(void* context, uint32_t arg) { + UNUSED(context); UNUSED(arg); - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); - furi_record_close(RECORD_LOADER); - return 0; -} -static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { - FuriThread* thread = context; - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void updater_start_app() { FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { return; @@ -110,11 +98,9 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = - furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); - furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); - furi_thread_set_state_context(thread, thread); - furi_thread_start(thread); + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start(loader, "UpdaterApp", NULL); + furi_record_close(RECORD_LOADER); } void updater_on_system_start() { @@ -126,7 +112,7 @@ void updater_on_system_start() { UNUSED(updater_cli_ep); #endif #ifndef FURI_RAM_EXEC - updater_start_app(); + furi_timer_pending_callback(updater_start_app, NULL, 0); #else UNUSED(updater_start_app); #endif diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 63024ced9..5d2477464 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); // Format LFS before restoring backup on next boot furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); - +#ifdef FURI_NDEBUG + // Production + furi_hal_rtc_set_log_level(FuriLogLevelDefault); + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); +#endif update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); success = true; } while(false); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bc6844d35..f83f6405b 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,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1c8424fe8..8a4e06303 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,24.0,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1073,6 +1073,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1562,7 +1564,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1571,6 +1573,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index d0bce5038..3fbe384e3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,11 +1,12 @@ #include +#include #include #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) void furi_hal_cortex_init_early() { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; @@ -38,4 +39,71 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { while(!furi_hal_cortex_timer_is_expired(cortex_timer)) ; -} \ No newline at end of file +} + +// Duck ST +#undef COMP0 +#undef COMP1 +#undef COMP2 +#undef COMP3 + +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size) { + uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); + + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = value; + (DWT->MASK0) = mask; + (DWT->FUNCTION0) = function_reg; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = value; + (DWT->MASK1) = mask; + (DWT->FUNCTION1) = function_reg; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = value; + (DWT->MASK2) = mask; + (DWT->FUNCTION2) = function_reg; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = value; + (DWT->MASK3) = mask; + (DWT->FUNCTION3) = function_reg; + break; + default: + furi_crash("Invalid parameter"); + } +} + +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = 0; + (DWT->MASK0) = 0; + (DWT->FUNCTION0) = 0; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = 0; + (DWT->MASK1) = 0; + (DWT->FUNCTION1) = 0; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = 0; + (DWT->MASK2) = 0; + (DWT->FUNCTION2) = 0; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = 0; + (DWT->MASK3) = 0; + (DWT->FUNCTION3) = 0; + break; + default: + furi_crash("Invalid parameter"); + } +} diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/firmware/targets/furi_hal_include/furi_hal_cortex.h index 91596ffe3..ebabbabfd 100644 --- a/firmware/targets/furi_hal_include/furi_hal_cortex.h +++ b/firmware/targets/furi_hal_include/furi_hal_cortex.h @@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); */ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); +typedef enum { + FuriHalCortexComp0, + FuriHalCortexComp1, + FuriHalCortexComp2, + FuriHalCortexComp3, +} FuriHalCortexComp; + +typedef enum { + FuriHalCortexCompSizeWord = 0b10, + FuriHalCortexCompSizeHalfWord = 0b01, + FuriHalCortexCompSizeByte = 0b00, +} FuriHalCortexCompSize; + +typedef enum { + FuriHalCortexCompFunctionPC = 0b100, + FuriHalCortexCompFunctionRead = 0b101, + FuriHalCortexCompFunctionWrite = 0b110, + FuriHalCortexCompFunctionReadWrite = 0b110, +} FuriHalCortexCompFunction; + +/** Enable DWT comparator + * + * Allows to programmatically set instruction/data breakpoints. + * + * More details on how it works can be found in armv7m official documentation: + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn + * + * @param[in] comp The Comparator + * @param[in] function The Comparator Function to use + * @param[in] value The value + * @param[in] mask The mask + * @param[in] size The size + */ +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size); + +/** Reset DWT comparator + * + * @param[in] comp The Comparator + */ +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index d78070d61..facbcb411 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( void furi_thread_free(FuriThread* thread) { furi_assert(thread); - furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); - if(thread->appid) free((void*)thread->appid); + // Ensure that use join before free + furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(thread->task_handle == NULL); + + if(thread->name) free(thread->name); + if(thread->appid) free(thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); + if(thread->name) free(thread->name); thread->name = name ? strdup(name) : NULL; } void furi_thread_set_appid(FuriThread* thread, const char* appid) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->appid) free((void*)thread->appid); + if(thread->appid) free(thread->appid); thread->appid = appid ? strdup(appid) : NULL; } @@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { if(thread) { // clear thread local storage vTaskSetThreadLocalStoragePointer(task, 0, NULL); - + furi_assert(thread->task_handle == task); thread->task_handle = NULL; } } @@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { FuriThread* furi_thread_get_current() { FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); - furi_assert(thread != NULL); return thread; } @@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; - - return true; } FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); return thread->output.write_callback; } size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); if(size == 0 || data == NULL) { return __furi_thread_stdout_flush(thread); } else { @@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { } int32_t furi_thread_stdout_flush() { - return __furi_thread_stdout_flush(furi_thread_get_current()); + FuriThread* thread = furi_thread_get_current(); + furi_assert(thread); + return __furi_thread_stdout_flush(thread); } void furi_thread_suspend(FuriThreadId thread_id) { diff --git a/furi/core/thread.h b/furi/core/thread.h index b11a225b5..022894ee8 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); /** Get FuriThread instance for current thread * - * @return FuriThread* + * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi */ FuriThread* furi_thread_get_current(); @@ -288,12 +288,10 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); /** Set STDOUT callback for thread - * + * * @param callback callback or NULL to clear - * - * @return true on success, otherwise fail */ -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); /** Write data to buffered STDOUT * diff --git a/furi/core/timer.c b/furi/core/timer.c index 4b6ccecba..7743ffe70 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { /* Return 0: not running, 1: running */ return (uint32_t)xTimerIsTimerActive(hTimer); } + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { + BaseType_t ret = pdFAIL; + if(furi_kernel_is_irq_or_masked()) { + ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); + } else { + ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); + } + furi_check(ret == pdPASS); +} \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index e79c1868d..3f43de5fd 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); + #ifdef __cplusplus } #endif From 7ddde7e6ca333e63f6ec3073cadfa0f9ee6c8f83 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 16:09:06 +0300 Subject: [PATCH 132/216] Fuzzers remove excessive free's thanks to @Willy-JL --- applications/external/flipfrid/flipfrid.c | 3 --- applications/external/ibtn_fuzzer/ibtnfuzzer.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/applications/external/flipfrid/flipfrid.c b/applications/external/flipfrid/flipfrid.c index 4608bab16..1cf7be865 100644 --- a/applications/external/flipfrid/flipfrid.c +++ b/applications/external/flipfrid/flipfrid.c @@ -118,9 +118,6 @@ void flipfrid_free(FlipFridState* flipfrid) { furi_string_free(flipfrid->main_menu_proto_items[i]); } - free(flipfrid->data); - free(flipfrid->payload); - // The rest free(flipfrid); } diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.c b/applications/external/ibtn_fuzzer/ibtnfuzzer.c index d385a22d2..825a55560 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.c +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.c @@ -120,9 +120,6 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) { furi_string_free(ibtnfuzzer->main_menu_proto_items[i]); } - free(ibtnfuzzer->data); - free(ibtnfuzzer->payload); - // The rest free(ibtnfuzzer); } From 1feb876a32efa8c2de59e4c218312e8a1533c160 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 5 May 2023 17:58:58 +0300 Subject: [PATCH 133/216] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c6260e0..459a9d6c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ ### New changes +* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues! +* Plugins: RFID and iButton Fuzzer remove excessive free's (thanks @Willy-JL) +* Plugins: Use COUNT_OF in mouse jiggler * Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) +* About: Don't show 00 on about screens +* SubGHz: Combine FuriString allocs and other small changes * Infrared: Updated universal remote assets (by @amec0e | PR #454) * Update slideshow: Replace QR code with good old link +* OFW: Various Furi/FuriHal bug fixes and improvements -> **Breaking API change, api was changed from 24.x to 26.x** +* OFW: Loader refactoring, part 1 -> **Breaking API change, api was changed from 23.x to 24.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** * OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements * OFW: Added API version to device info * OFW: Gui: relax some asserts in view From 49df6a89b597e8dfd065ffe5339c10ffd0c8d579 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Fri, 5 May 2023 23:24:38 +0100 Subject: [PATCH 134/216] Temp fix for mobile app pairing --- firmware/targets/f7/furi_hal/furi_hal_version.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 607560460..43a48d136 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -124,7 +124,11 @@ static void furi_hal_version_set_name(const char* name) { } uint32_t company_id = LL_FLASH_GetSTCompanyID(); - uint32_t device_id = LL_FLASH_GetDeviceID(); + // uint32_t device_id = LL_FLASH_GetDeviceID(); + // Somehow some new flippers return 0x27 instead of 0x26 + // Mobile apps expects it to return 0x26 (and clearly STM too) + // Temporarely hardcoded until cause / fix is found + uint32_t device_id = 0x26; furi_hal_version.ble_mac[0] = (uint8_t)(udn & 0x000000FF); furi_hal_version.ble_mac[1] = (uint8_t)((udn & 0x0000FF00) >> 8); furi_hal_version.ble_mac[2] = (uint8_t)((udn & 0x00FF0000) >> 16); From ff24bf6829a4030764a0525dd200174c7dd92ddf Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 02:00:26 +0300 Subject: [PATCH 135/216] SubGhz: add SubGhzThresholdRssi --- .../subghz/helpers/subghz_threshold_rssi.c | 60 +++++++++++++++++++ .../subghz/helpers/subghz_threshold_rssi.h | 43 +++++++++++++ .../subghz/scenes/subghz_scene_read_raw.c | 51 +++++----------- .../subghz/scenes/subghz_scene_receiver.c | 7 ++- .../scenes/subghz_scene_receiver_config.c | 6 +- applications/main/subghz/subghz.c | 11 +++- applications/main/subghz/subghz_i.h | 13 ++-- 7 files changed, 143 insertions(+), 48 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.c create mode 100644 applications/main/subghz/helpers/subghz_threshold_rssi.h diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c new file mode 100644 index 000000000..04a06bc17 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -0,0 +1,60 @@ +#include "subghz_threshold_rssi.h" +#include +#include "../subghz_i.h" + +#define TAG "SubGhzThresholdRssi" +#define THRESHOLD_RSSI_LOW_COUNT 10 + +struct SubGhzThresholdRssi { + float threshold_rssi; + uint8_t threshold_rssi_low_count; +}; + +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) { + SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi)); + instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + return instance; +} + +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) { + furi_assert(instance); + free(instance); +} + +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) { + furi_assert(instance); + instance->threshold_rssi = rssi; +} + +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { + furi_assert(instance); + return instance->threshold_rssi; +} + +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { + furi_assert(instance); + float rssi = furi_hal_subghz_get_rssi(); + SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; + + if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { + ret.is_above = true; + } else { + if(rssi < instance->threshold_rssi) { + instance->threshold_rssi_low_count++; + if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) { + instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT; + } + ret.is_above = false; + } else { + instance->threshold_rssi_low_count = 0; + } + + if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) { + ret.is_above = false; + } else { + ret.is_above = true; + } + } + return ret; +} diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h new file mode 100644 index 000000000..e28092acb --- /dev/null +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +typedef struct { + float rssi; /**< Current RSSI */ + bool is_above; /**< Exceeded threshold level */ +} SubGhzThresholdRssiData; + +typedef struct SubGhzThresholdRssi SubGhzThresholdRssi; + +/** Allocate SubGhzThresholdRssi + * + * @return SubGhzThresholdRssi* + */ +SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void); + +/** Free SubGhzThresholdRssi + * + * @param instance Pointer to a SubGhzThresholdRssi + */ +void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance); + +/** Set threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi RSSI threshold + */ +void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi); + +/** Get threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return float RSSI threshold + */ +float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); + +/** Check threshold + * + * @param instance Pointer to a SubGhzThresholdRssi + * @return SubGhzThresholdRssiData + */ +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 6a881cba4..35b3fa58e 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -7,7 +7,6 @@ #define RAW_FILE_NAME "RAW_" #define TAG "SubGhzSceneReadRAW" -#define RAW_THRESHOLD_RSSI_LOW_COUNT 10 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -75,7 +74,10 @@ void subghz_scene_read_raw_on_enter(void* context) { switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi); + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz_threshold_rssi_get(subghz->threshold_rssi)); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); @@ -83,7 +85,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); + subghz_threshold_rssi_get(subghz->threshold_rssi)); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; case SubGhzRxKeyStateRAWSave: @@ -92,7 +94,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), - subghz->txrx->raw_threshold_rssi); + subghz_threshold_rssi_get(subghz->threshold_rssi)); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; default: @@ -100,7 +102,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", - subghz->txrx->raw_threshold_rssi); + subghz_threshold_rssi_get(subghz->threshold_rssi)); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; } @@ -238,7 +240,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", - subghz->txrx->raw_threshold_rssi); + subghz_threshold_rssi_get(subghz->threshold_rssi)); } else { if(scene_manager_has_previous_scene( subghz->scene_manager, SubGhzSceneSaved) || @@ -311,7 +313,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; if(subghz_protocol_raw_save_to_file_init( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, RAW_FILE_NAME, @@ -359,40 +360,18 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); + subghz_read_raw_update_sample_write( subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); - float rssi = furi_hal_subghz_get_rssi(); - - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - } else { - if(rssi < subghz->txrx->raw_threshold_rssi) { - subghz->txrx->raw_threshold_rssi_low_count++; - if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT; - } - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - } else { - subghz->txrx->raw_threshold_rssi_low_count = 0; - } - - if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); - subghz_speaker_mute(subghz); - } else { - subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); - subghz_speaker_unmute(subghz); - } - } + SubGhzThresholdRssiData ret_rssi = + subghz_threshold_get_rssi_data(subghz->threshold_rssi); + subghz_read_raw_add_data_rssi( + subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); + subghz_protocol_raw_save_to_file_pause( + (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, !ret_rssi.is_above); break; case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index fd8d9b70e..18008674d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -283,10 +283,11 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { } //get RSSI - float rssi = furi_hal_subghz_get_rssi(); - subghz_receiver_rssi(subghz->subghz_receiver, rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + + subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); + (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, ret_rssi.rssi); switch(subghz->state_notifications) { case SubGhzNotificationStateRx: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 68c5b4b7a..bd9780428 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -234,7 +234,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, raw_threshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_threshold_rssi_value[index]; + subghz_threshold_rssi_set(subghz->threshold_rssi, raw_threshold_rssi_value[index]); } static void subghz_scene_receiver_config_set_starline(VariableItem* item) { @@ -400,7 +400,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_threshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz_threshold_rssi_get(subghz->threshold_rssi), + raw_threshold_rssi_value, + RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, raw_threshold_rssi_text[value_index]); } diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 47da7ae40..4bbdba6c5 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -255,6 +255,10 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { #endif subghz_setting_set_default_frequency(subghz->setting, subghz->last_settings->frequency); } + + //init threshold rssi + subghz->threshold_rssi = subghz_threshold_rssi_alloc(); + //init Worker & Protocol & History & KeyBoard subghz->lock = SubGhzLockOff; subghz->txrx = malloc(sizeof(SubGhzTxRx)); @@ -275,7 +279,6 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->history = subghz_history_alloc(); } - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->fff_data = flipper_format_string_alloc(); @@ -386,11 +389,15 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - //setting + // setting subghz_setting_free(subghz->setting); if(!alloc_for_tx_only) { subghz_last_settings_free(subghz->last_settings); } + + // threshold rssi + subghz_threshold_rssi_free(subghz->threshold_rssi); + //Worker & Protocol & History subghz_receiver_free(subghz->txrx->receiver); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index faae35fa2..9c58af7bb 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -41,6 +41,8 @@ #include "rpc/rpc_app.h" +#include "helpers/subghz_threshold_rssi.h" + #define SUBGHZ_MAX_LEN_NAME 64 #define SUBGHZ_EXT_PRESET_NAME true @@ -70,20 +72,19 @@ struct SubGhzTxRx { SubGhzRadioPreset* preset; SubGhzHistory* history; uint16_t idx_menu_chosen; + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + SubGhzTxRxState txrx_state; SubGhzHopperState hopper_state; SubGhzSpeakerState speaker_state; bool ignore_starline; bool ignore_auto_alarms; bool ignore_magellan; - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; + SubGhzRxKeyState rx_key_state; bool debug_pin_state; - - float raw_threshold_rssi; - uint8_t raw_threshold_rssi_low_count; }; typedef struct SubGhzTxRx SubGhzTxRx; @@ -131,6 +132,8 @@ struct SubGhz { SubGhzDecodeRawState decode_raw_state; SubGhzFileEncoderWorker* decode_raw_file_worker_encoder; + SubGhzThresholdRssi* threshold_rssi; + void* rpc_ctx; }; From 8fa7d16c5f976c607af7386b9b0ee217ec8c9089 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 01:43:09 +0100 Subject: [PATCH 136/216] Merge branch 'ul-dev' into xfw-dev --- .gitignore | 1 + .../hid_app/views/hid_mouse_jiggler.c | 6 +- .../views/pocsag_pager_receiver.c | 6 +- .../views/weather_station_receiver.c | 6 +- .../subghz/scenes/subghz_scene_decode_raw.c | 28 +- .../main/subghz/scenes/subghz_scene_delete.c | 10 +- .../subghz/scenes/subghz_scene_delete_raw.c | 7 +- .../subghz/scenes/subghz_scene_read_raw.c | 16 +- .../subghz/scenes/subghz_scene_receiver.c | 24 +- .../scenes/subghz_scene_receiver_info.c | 10 +- .../main/subghz/scenes/subghz_scene_rpc.c | 3 +- .../subghz/scenes/subghz_scene_save_name.c | 8 +- .../subghz/scenes/subghz_scene_show_error.c | 11 +- .../subghz/scenes/subghz_scene_transmitter.c | 13 +- applications/main/subghz/subghz_cli.c | 36 +- applications/main/subghz/subghz_history.c | 3 +- applications/main/subghz/subghz_i.c | 22 +- applications/main/subghz/views/receiver.c | 3 +- applications/main/subghz/views/transmitter.c | 4 +- applications/main/subghz/views/transmitter.h | 4 +- applications/services/cli/cli_commands.c | 2 - .../desktop/scenes/desktop_scene_lock_menu.c | 3 +- .../desktop/scenes/desktop_scene_main.c | 8 +- applications/services/loader/application.fam | 9 + applications/services/loader/loader.c | 699 ++++++------------ applications/services/loader/loader.h | 13 +- applications/services/loader/loader_cli.c | 117 +++ applications/services/loader/loader_i.h | 80 +- applications/services/loader/loader_menu.c | 256 +++++++ applications/services/loader/loader_menu.h | 30 + applications/services/rpc/rpc.c | 50 +- .../services/storage/storage_external_api.c | 1 + .../services/storage/storages/storage_ext.c | 1 + applications/settings/about/about.c | 4 +- .../power_settings_app/views/battery_info.c | 4 +- .../settings/system/system_settings.c | 1 - applications/system/updater/cli/updater_cli.c | 26 +- .../updater/util/update_task_worker_flasher.c | 6 +- firmware/targets/f18/api_symbols.csv | 12 +- firmware/targets/f7/api_symbols.csv | 14 +- .../targets/f7/furi_hal/furi_hal_cortex.c | 72 +- .../furi_hal_include/furi_hal_cortex.h | 47 ++ furi/core/thread.c | 30 +- furi/core/thread.h | 8 +- furi/core/timer.c | 10 + furi/core/timer.h | 4 + 46 files changed, 1007 insertions(+), 721 deletions(-) create mode 100644 applications/services/loader/loader_cli.c create mode 100644 applications/services/loader/loader_menu.c create mode 100644 applications/services/loader/loader_menu.h diff --git a/.gitignore b/.gitignore index d6a2dc470..48b5ed8b0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp *.swo *.gdb_history +*.old # LSP diff --git a/applications/external/hid_app/views/hid_mouse_jiggler.c b/applications/external/hid_app/views/hid_mouse_jiggler.c index 120d5bc34..09c14c668 100644 --- a/applications/external/hid_app/views/hid_mouse_jiggler.c +++ b/applications/external/hid_app/views/hid_mouse_jiggler.c @@ -6,8 +6,6 @@ #define TAG "HidMouseJiggler" -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - struct HidMouseJiggler { View* view; Hid* hid; @@ -44,7 +42,7 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); canvas_set_font(canvas, FontSecondary); if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); @@ -116,7 +114,7 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { consumed = true; } if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { + model->interval_idx < (int)COUNT_OF(intervals) - 1) { model->interval_idx++; consumed = true; } diff --git a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c index 532f41984..64939a956 100644 --- a/applications/external/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/external/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -69,10 +69,10 @@ void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { instance->view, PCSGReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/external/weather_station/views/weather_station_receiver.c b/applications/external/weather_station/views/weather_station_receiver.c index 62f1adad0..e994e7830 100644 --- a/applications/external/weather_station/views/weather_station_receiver.c +++ b/applications/external/weather_station/views/weather_station_receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { instance->view, WSReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ac4fcccd..b9f2d236b 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -24,14 +24,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -62,11 +58,9 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -90,8 +84,7 @@ static void subghz_scene_add_to_history_callback( } bool subghz_scene_decode_raw_start(SubGhz* subghz) { - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); bool success = false; do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { @@ -148,8 +141,7 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { } // Update progress info - FuriString* progress_str; - progress_str = furi_string_alloc(); + FuriString* progress_str = furi_string_alloc(); subghz_file_encoder_worker_get_text_progress( subghz->decode_raw_file_worker_encoder, progress_str); @@ -164,10 +156,8 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 94814b143..4cad14bbf 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -11,13 +11,9 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co void subghz_scene_delete_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index fa4fc6f64..ee7983dfd 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -15,11 +15,8 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; FuriString* file_name; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index db2cf4763..e3eb5bdd1 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -12,8 +12,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; //set the path to read the file - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); do { if(!flipper_format_rewind(subghz->txrx->fff_data)) { FURI_LOG_E(TAG, "Rewind error"); @@ -38,11 +37,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz, frequency_str, NULL); @@ -74,8 +70,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: @@ -313,8 +308,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index b17a0700b..fd8d9b70e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -39,14 +39,10 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; - FuriString* history_stat_str; - history_stat_str = furi_string_alloc(); + FuriString* history_stat_str = furi_string_alloc(); if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { - FuriString* frequency_str; - FuriString* modulation_str; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { @@ -90,12 +86,12 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); + SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; + + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->txrx->history); - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { furi_string_reset(item_name); @@ -122,10 +118,8 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* item_name; - FuriString* item_time; - item_name = furi_string_alloc(); - item_time = furi_string_alloc(); + FuriString* item_name = furi_string_alloc(); + FuriString* item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 58e428785..a108132c0 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -49,13 +49,9 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { if(subghz_scene_receiver_info_update_parser(subghz)) { - FuriString* frequency_str; - FuriString* modulation_str; - FuriString* text; - - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - text = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); widget_add_string_element( diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 82ab184d1..13379490b 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -73,8 +73,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); furi_string_set(subghz->file_path, arg); result = true; - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); path_extract_filename(subghz->file_path, file_name, true); snprintf( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d3f5474be..2bb13f184 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -51,10 +51,8 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - FuriString* file_name; - FuriString* dir_name; - file_name = furi_string_alloc(); - dir_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* dir_name = furi_string_alloc(); if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; @@ -109,7 +107,7 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_scene_save_name_text_input_callback, subghz, subghz->file_name_tmp, - MAX_TEXT_INPUT_LEN, // buffer size + MAX_TEXT_INPUT_LEN, dev_name_empty); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( diff --git a/applications/main/subghz/scenes/subghz_scene_show_error.c b/applications/main/subghz/scenes/subghz_scene_show_error.c index 107189cae..4544260ef 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error.c @@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + SubGhzCustomEvent scene_state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError); if(event.type == SceneManagerEventTypeBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { return false; } else { scene_manager_search_and_switch_to_previous_scene( @@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorOk) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } return true; } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == - SubGhzCustomEventManagerSet) { + if(scene_state == SubGhzCustomEventManagerSet) { //exit app if(!scene_manager_previous_scene(subghz->scene_manager)) { scene_manager_stop(subghz->scene_manager); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 78b26688f..77601c08a 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -17,14 +17,11 @@ bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; if(subghz->txrx->decoder_result) { - FuriString* key_str; - FuriString* frequency_str; - FuriString* modulation_str; + FuriString* key_str = furi_string_alloc(); + FuriString* frequency_str = furi_string_alloc(); + FuriString* modulation_str = furi_string_alloc(); - key_str = furi_string_alloc(); - frequency_str = furi_string_alloc(); - modulation_str = furi_string_alloc(); - uint8_t show_button = 0; + bool show_button = false; if(subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { @@ -32,7 +29,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { - show_button = 1; + show_button = true; } subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index be7143643..815857cc9 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -215,8 +215,7 @@ static void subghz_cli_command_rx_callback( SubGhzCliCommandRx* instance = context; instance->packet_count++; - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); subghz_protocol_decoder_base_get_string(decoder_base, text); subghz_receiver_reset(receiver); printf("%s", furi_string_get_cstr(text)); @@ -384,14 +383,12 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { } void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); - FuriString* file_name; - file_name = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); furi_string_set(file_name, ANY_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool check_file = false; @@ -526,10 +523,8 @@ static void subghz_cli_command_encrypt_keeloq(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); SubGhzKeystore* keystore = subghz_keystore_alloc(); @@ -569,10 +564,8 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { UNUSED(cli); uint8_t iv[16]; - FuriString* source; - FuriString* destination; - source = furi_string_alloc(); - destination = furi_string_alloc(); + FuriString* source = furi_string_alloc(); + FuriString* destination = furi_string_alloc(); do { if(!args_read_string_and_trim(args, source)) { @@ -646,14 +639,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { size_t message_max_len = 64; uint8_t message[64] = {0}; - FuriString* input; - input = furi_string_alloc(); - FuriString* name; - name = furi_string_alloc(); - FuriString* output; - output = furi_string_alloc(); - FuriString* sysmsg; - sysmsg = furi_string_alloc(); + FuriString* input = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + FuriString* output = furi_string_alloc(); + FuriString* sysmsg = furi_string_alloc(); bool exit = false; SubGhzChatEvent chat_event; @@ -786,8 +775,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { } static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { - FuriString* cmd; - cmd = furi_string_alloc(); + FuriString* cmd = furi_string_alloc(); do { if(!args_read_string_and_trim(args, cmd)) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 3c018ec8b..396e28421 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -197,8 +197,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); - FuriString* text; - text = furi_string_alloc(); + FuriString* text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); item->preset = malloc(sizeof(SubGhzRadioPreset)); item->type = decoder_base->protocol->type; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index cbef8fe97..d21bdac41 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -145,8 +145,7 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { furi_assert(subghz); bool ret = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { if(!flipper_format_rewind(flipper_format)) { @@ -254,8 +253,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; - FuriString* temp_str; - temp_str = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; do { @@ -393,13 +391,9 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* temp_str; - FuriString* file_name; - FuriString* file_path; - - temp_str = furi_string_alloc(); - file_name = furi_string_alloc(); - file_path = furi_string_alloc(); + FuriString* temp_str = furi_string_alloc(); + FuriString* file_name = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); bool res = false; @@ -446,8 +440,7 @@ bool subghz_save_protocol_to_file( Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; - FuriString* file_dir; - file_dir = furi_string_alloc(); + FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { @@ -478,8 +471,7 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - FuriString* file_path; - file_path = furi_string_alloc(); + FuriString* file_path = furi_string_alloc(); DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 0d38503da..bcc7181f0 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -241,8 +241,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } bool scrollbar = model->history_item > 4; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* str_buff = furi_string_alloc(); SubGhzReceiverMenuItem* item_menu; diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 5667cd59f..48184cf39 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -21,7 +21,7 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button) { + bool show_button) { furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, @@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->preset_str); furi_string_reset(model->key_str); furi_string_reset(model->temp_button_id); - model->show_button = 0; + model->show_button = false; model->draw_temp_button = false; }, false); diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 1ae51afbd..e121c8746 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -7,7 +7,7 @@ typedef struct { FuriString* frequency_str; FuriString* preset_str; FuriString* key_str; - uint8_t show_button; + bool show_button; FuriString* temp_button_id; bool draw_temp_button; } SubGhzViewTransmitterModel; @@ -36,4 +36,4 @@ void subghz_view_transmitter_add_data_to_show( const char* key_str, const char* frequency_str, const char* preset_str, - uint8_t show_button); + bool show_button); diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index a652d0f0c..fc71aa31f 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -230,11 +230,9 @@ void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) { UNUSED(context); if(!furi_string_cmp(args, "0")) { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug disabled."); } else if(!furi_string_cmp(args, "1")) { furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); - loader_update_menu(); printf("Debug enabled."); } else { cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args)); diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index e68d28076..346283d1b 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -80,7 +80,8 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { switch(event.event) { case DesktopLockMenuEventSettings: desktop_scene_lock_menu_save_settings(desktop); - loader_show_settings(); + loader_show_settings(furi_record_open(RECORD_LOADER)); + furi_record_close(RECORD_LOADER); consumed = true; break; case DesktopLockMenuEventLock: diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 8be63bfe3..1bb194302 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -90,10 +90,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case DesktopMainEventOpenMenu: - loader_show_menu(); + case DesktopMainEventOpenMenu: { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_show_menu(loader); + furi_record_close(RECORD_LOADER); consumed = true; - break; + } break; case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); diff --git a/applications/services/loader/application.fam b/applications/services/loader/application.fam index 49f3c4148..f4d006e07 100644 --- a/applications/services/loader/application.fam +++ b/applications/services/loader/application.fam @@ -5,6 +5,7 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], + provides=["loader_start"], stack_size=2 * 1024, order=90, sdk_headers=[ @@ -12,3 +13,11 @@ App( "firmware_api/firmware_api.h", ], ) + +App( + appid="loader_start", + apptype=FlipperAppType.STARTUP, + entry_point="loader_on_system_start", + requires=["loader"], + order=90, +) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 808c8e18e..b9f47dcdd 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,23 +1,125 @@ -#include "applications.h" -#include -#include -#include "loader/loader.h" +#include "loader.h" #include "loader_i.h" -#include "applications/main/fap_loader/fap_loader_app.h" -#include -#include -#include -#include -#include -#include +#include "loader_menu.h" +#include +#include -#define TAG "LoaderSrv" +#define TAG "Loader" +#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF +// api -#define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) -#define LOADER_THREAD_FLAG_SHOW_SETTINGS (1 << 1) -#define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU | LOADER_THREAD_FLAG_SHOW_SETTINGS) +LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { + LoaderMessage message; + LoaderMessageLoaderStatusResult result; -static Loader* loader_instance = NULL; + message.type = LoaderMessageTypeStartByName; + message.start.name = name; + message.start.args = args; + message.api_lock = api_lock_alloc_locked(); + message.status_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +bool loader_lock(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeLock; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +void loader_unlock(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeUnlock; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +bool loader_is_locked(Loader* loader) { + LoaderMessage message; + LoaderMessageBoolResult result; + message.type = LoaderMessageTypeIsLocked; + message.api_lock = api_lock_alloc_locked(); + message.bool_value = &result; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + return result.value; +} + +void loader_show_menu(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowMenu; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +void loader_show_settings(Loader* loader) { + LoaderMessage message; + message.type = LoaderMessageTypeShowSettings; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +FuriPubSub* loader_get_pubsub(Loader* loader) { + furi_assert(loader); + // it's safe to return pubsub without locking + // because it's never freed and loader is never exited + // also the loader instance cannot be obtained until the pubsub is created + return loader->pubsub; +} + +// callbacks + +static void loader_menu_closed_callback(void* context) { + Loader* loader = context; + LoaderMessage message; + message.type = LoaderMessageTypeMenuClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); +} + +static void loader_menu_click_callback(const char* name, bool external, void* context) { + Loader* loader = context; + if(external) { + loader_start(loader, FAP_LOADER_APP_NAME, name); + } else { + loader_start(loader, name, NULL); + } +} + +static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { + furi_assert(context); + + Loader* loader = context; + LoaderEvent event; + + if(thread_state == FuriThreadStateRunning) { + event.type = LoaderEventTypeApplicationStarted; + furi_pubsub_publish(loader->pubsub, &event); + } else if(thread_state == FuriThreadStateStopped) { + LoaderMessage message; + message.type = LoaderMessageTypeAppClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); + } +} + +// implementation + +static Loader* loader_alloc() { + Loader* loader = malloc(sizeof(Loader)); + loader->pubsub = furi_pubsub_alloc(); + loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); + loader->loader_menu = NULL; + loader->app.args = NULL; + loader->app.name = NULL; + loader->app.thread = NULL; + loader->app.insomniac = false; + return loader; +} static FlipperApplication const* loader_find_application_by_name_in_list( const char* name, @@ -31,46 +133,7 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -static bool - loader_start_application(const FlipperApplication* application, const char* arguments) { - if(application->app == NULL) { - arguments = application->appid; - application = loader_find_application_by_name_in_list( - FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); - } - loader_instance->application = application; - - furi_assert(loader_instance->application_arguments == NULL); - if(arguments && strlen(arguments) > 0) { - loader_instance->application_arguments = strdup(arguments); - FURI_LOG_I(TAG, "Starting: %s, args: %s", loader_instance->application->name, arguments); - } else { - FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name); - } - - FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); - if(mode > FuriHalRtcHeapTrackModeNone) { - furi_thread_enable_heap_trace(loader_instance->application_thread); - } else { - furi_thread_disable_heap_trace(loader_instance->application_thread); - } - - furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name); - furi_thread_set_appid( - loader_instance->application_thread, loader_instance->application->appid); - furi_thread_set_stack_size( - loader_instance->application_thread, loader_instance->application->stack_size); - furi_thread_set_context( - loader_instance->application_thread, loader_instance->application_arguments); - furi_thread_set_callback( - loader_instance->application_thread, loader_instance->application->app); - - furi_thread_start(loader_instance->application_thread); - - return true; -} - -const FlipperApplication* loader_find_application_by_name(const char* name) { +static const FlipperApplication* loader_find_application_by_name(const char* name) { const FlipperApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { @@ -85,449 +148,177 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { return application; } -static void loader_menu_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const FlipperApplication* application = _ctx; +static void + loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); - furi_assert(application->app); - furi_assert(application->name); - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; + if(app->app == NULL) { + args = app->appid; + app = loader_find_application_by_name_in_list( + FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); } - loader_start_application(application, NULL); -} - -static void loader_external_callback(void* _ctx, uint32_t index) { - UNUSED(index); - const char* path = _ctx; - const FlipperApplication* app = loader_find_application_by_name_in_list( - FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT); - - furi_assert(path); - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); } - loader_start_application(app, path); -} + // store name + furi_assert(loader->app.name == NULL); + loader->app.name = strdup(app->name); -static void loader_submenu_callback(void* context, uint32_t index) { - UNUSED(index); - uint32_t view_id = (uint32_t)context; - view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); -} + // setup app thread + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); -static void loader_cli_print_usage() { - printf("Usage:\r\n"); - printf("loader \r\n"); - printf("Cmd list:\r\n"); - printf("\tlist\t - List available applications\r\n"); - printf("\topen \t - Open application by name\r\n"); - printf("\tinfo\t - Show loader state\r\n"); -} - -static void loader_cli_open(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - if(loader_is_locked(instance)) { - if(instance->application) { - furi_assert(instance->application->name); - printf("Can't start, %s application is running", instance->application->name); - } else { - printf("Can't start, furi application is running"); - } - return; - } - - FuriString* application_name; - application_name = furi_string_alloc(); - - do { - if(!args_read_probably_quoted_string_and_trim(args, application_name)) { - printf("No application provided\r\n"); - break; - } - - const FlipperApplication* application = - loader_find_application_by_name(furi_string_get_cstr(application_name)); - if(!application) { - printf("%s doesn't exists\r\n", furi_string_get_cstr(application_name)); - break; - } - - furi_string_trim(args); - if(!loader_start_application(application, furi_string_get_cstr(args))) { - printf("Can't start, furi application is running"); - return; - } else { - // We must to increment lock counter to keep balance - // TODO: rewrite whole thing, it's complex as hell - FURI_CRITICAL_ENTER(); - instance->lock_count++; - FURI_CRITICAL_EXIT(); - } - } while(false); - - furi_string_free(application_name); -} - -static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - UNUSED(instance); - printf("Applications:\r\n"); - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); - } -} - -static void loader_cli_info(Cli* cli, FuriString* args, Loader* instance) { - UNUSED(cli); - UNUSED(args); - if(!loader_is_locked(instance)) { - printf("No application is running\r\n"); + // setup heap trace + FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); + if(mode > FuriHalRtcHeapTrackModeNone) { + furi_thread_enable_heap_trace(loader->app.thread); } else { - printf("Running application: "); - if(instance->application) { - furi_assert(instance->application->name); - printf("%s\r\n", instance->application->name); - } else { - printf("unknown\r\n"); - } + furi_thread_disable_heap_trace(loader->app.thread); + } + + // setup insomnia + if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + furi_hal_power_insomnia_enter(); + loader->app.insomniac = true; + } else { + loader->app.insomniac = false; + } + + // setup app thread callbacks + furi_thread_set_state_context(loader->app.thread, loader); + furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); + + // start app thread + furi_thread_start(loader->app.thread); +} + +// process messages + +static void loader_do_menu_show(Loader* loader, bool settings) { + if(!loader->loader_menu) { + loader->loader_menu = loader_menu_alloc(); + loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); + loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); + loader_menu_start(loader->loader_menu, settings); } } -static void loader_cli(Cli* cli, FuriString* args, void* _ctx) { - furi_assert(_ctx); - Loader* instance = _ctx; - - FuriString* cmd; - cmd = furi_string_alloc(); - - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(cli, args, instance); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(cli, args, instance); - break; - } - - loader_cli_print_usage(); - } while(false); - - furi_string_free(cmd); +static void loader_do_menu_closed(Loader* loader) { + if(loader->loader_menu) { + loader_menu_stop(loader->loader_menu); + loader_menu_free(loader->loader_menu); + loader->loader_menu = NULL; + } } -LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { - UNUSED(instance); - furi_assert(name); +static bool loader_do_is_locked(Loader* loader) { + return loader->app.thread != NULL; +} - const FlipperApplication* application = loader_find_application_by_name(name); - - if(!application) { - FURI_LOG_E(TAG, "Can't find application with name %s", name); - return LoaderStatusErrorUnknownApp; - } - - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); +static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { + if(loader_do_is_locked(loader)) { return LoaderStatusErrorAppStarted; } - if(!loader_start_application(application, args)) { - return LoaderStatusErrorInternal; + const FlipperApplication* app = loader_find_application_by_name(name); + + if(!app) { + return LoaderStatusErrorUnknownApp; } + loader_start_internal_app(loader, app, args); return LoaderStatusOk; } -bool loader_lock(Loader* instance) { - FURI_CRITICAL_ENTER(); - bool result = false; - if(instance->lock_count == 0) { - instance->lock_count++; - result = true; - } - FURI_CRITICAL_EXIT(); - return result; -} - -void loader_unlock(Loader* instance) { - FURI_CRITICAL_ENTER(); - if(instance->lock_count > 0) instance->lock_count--; - FURI_CRITICAL_EXIT(); -} - -bool loader_is_locked(const Loader* instance) { - return instance->lock_count > 0; -} - -static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - - Loader* instance = context; - LoaderEvent event; - - if(thread_state == FuriThreadStateRunning) { - event.type = LoaderEventTypeApplicationStarted; - furi_pubsub_publish(loader_instance->pubsub, &event); - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_enter(); - } - } else if(thread_state == FuriThreadStateStopped) { - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); - - if(loader_instance->application_arguments) { - free(loader_instance->application_arguments); - loader_instance->application_arguments = NULL; - } - - if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) { - furi_hal_power_insomnia_exit(); - } - loader_unlock(instance); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader_instance->pubsub, &event); - } -} - -static uint32_t loader_hide_menu(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -static uint32_t loader_back_to_primary_menu(void* context) { - furi_assert(context); - Submenu* submenu = context; - submenu_set_selected_item(submenu, 0); - return LoaderMenuViewPrimary; -} - -static Loader* loader_alloc() { - Loader* instance = malloc(sizeof(Loader)); - - instance->application_thread = furi_thread_alloc(); - - furi_thread_set_state_context(instance->application_thread, instance); - furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback); - - instance->pubsub = furi_pubsub_alloc(); - -#ifdef SRV_CLI - instance->cli = furi_record_open(RECORD_CLI); - cli_add_command( - instance->cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, instance); -#else - UNUSED(loader_cli); -#endif - - instance->loader_thread = furi_thread_get_current_id(); - - // Gui - instance->gui = furi_record_open(RECORD_GUI); - instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_attach_to_gui( - instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); - // Primary menu - instance->primary_menu = menu_alloc(); - view_set_previous_callback(menu_get_view(instance->primary_menu), loader_hide_menu); - view_dispatcher_add_view( - instance->view_dispatcher, LoaderMenuViewPrimary, menu_get_view(instance->primary_menu)); - // Settings menu - instance->settings_menu = submenu_alloc(); - view_set_context(submenu_get_view(instance->settings_menu), instance->settings_menu); - view_set_previous_callback( - submenu_get_view(instance->settings_menu), loader_back_to_primary_menu); - view_dispatcher_add_view( - instance->view_dispatcher, - LoaderMenuViewSettings, - submenu_get_view(instance->settings_menu)); - - view_dispatcher_enable_queue(instance->view_dispatcher); - - return instance; -} - -static void loader_free(Loader* instance) { - furi_assert(instance); - - if(instance->cli) { - furi_record_close(RECORD_CLI); - } - - furi_pubsub_free(instance->pubsub); - - furi_thread_free(instance->application_thread); - - menu_free(loader_instance->primary_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - submenu_free(loader_instance->settings_menu); - view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_free(loader_instance->view_dispatcher); - - furi_record_close(RECORD_GUI); - - free(instance); - instance = NULL; -} - -bool loader_load_fap_meta(Storage* storage, FuriString* path, FuriString* name, const Icon** icon) { - *icon = NULL; - uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); - if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { - free(icon_buf); - icon_buf = NULL; +static bool loader_do_lock(Loader* loader) { + if(loader->app.thread) { return false; } - *icon = malloc(sizeof(Icon)); - FURI_CONST_ASSIGN((*icon)->frame_count, 1); - FURI_CONST_ASSIGN((*icon)->frame_rate, 0); - FURI_CONST_ASSIGN((*icon)->width, 10); - FURI_CONST_ASSIGN((*icon)->height, 10); - FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); - FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + + loader->app.thread = (FuriThread*)LOADER_MAGIC_THREAD_VALUE; return true; } -static void loader_build_menu() { - FURI_LOG_I(TAG, "Building main menu"); - size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - loader_instance->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - i, - loader_menu_callback, - (void*)&FLIPPER_APPS[i]); +static void loader_do_unlock(Loader* loader) { + furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + loader->app.thread = NULL; +} + +static void loader_do_app_closed(Loader* loader) { + furi_assert(loader->app.thread); + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + if(loader->app.args) { + free(loader->app.args); + loader->app.args = NULL; } - menu_add_item( - loader_instance->primary_menu, - "Settings", - &A_Settings_14, - i++, - loader_submenu_callback, - (void*)LoaderMenuViewSettings); - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* path = furi_string_alloc(); - FuriString* name = furi_string_alloc(); - Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - while(stream_read_line(stream, path)) { - furi_string_replace_all(path, "\r", ""); - furi_string_replace_all(path, "\n", ""); - const Icon* icon; - if(!loader_load_fap_meta(storage, path, name, &icon)) continue; - menu_add_item( - loader_instance->primary_menu, - strdup(furi_string_get_cstr(name)), - icon, - i++, - loader_external_callback, - (void*)strdup(furi_string_get_cstr(path))); - } + if(loader->app.insomniac) { + furi_hal_power_insomnia_exit(); } - file_stream_close(stream); - stream_free(stream); - furi_string_free(name); - furi_string_free(path); - furi_record_close(RECORD_STORAGE); + + free(loader->app.name); + loader->app.name = NULL; + + furi_thread_join(loader->app.thread); + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; } -static void loader_build_submenu() { - FURI_LOG_I(TAG, "Building settings menu"); - for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { - submenu_add_item( - loader_instance->settings_menu, - FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_callback, - (void*)&FLIPPER_SETTINGS_APPS[i]); - } -} - -void loader_show_menu() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); -} - -void loader_show_settings() { - furi_assert(loader_instance); - furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_SETTINGS); -} - -void loader_update_menu() { - menu_reset(loader_instance->primary_menu); - loader_build_menu(); -} +// app int32_t loader_srv(void* p) { UNUSED(p); + Loader* loader = loader_alloc(); + furi_record_create(RECORD_LOADER, loader); + FURI_LOG_I(TAG, "Executing system start hooks"); for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { FLIPPER_ON_SYSTEM_START[i](); } - FURI_LOG_I(TAG, "Starting"); - loader_instance = loader_alloc(); - - loader_build_menu(); - loader_build_submenu(); - - FURI_LOG_I(TAG, "Started"); - - furi_record_create(RECORD_LOADER, loader_instance); - if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); } - while(1) { - uint32_t flags = - furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); - if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { - menu_set_selected_item(loader_instance->primary_menu, 0); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_run(loader_instance->view_dispatcher); - } else if(flags & LOADER_THREAD_FLAG_SHOW_SETTINGS) { - submenu_set_selected_item(loader_instance->settings_menu, 0); - view_set_previous_callback( - submenu_get_view(loader_instance->settings_menu), loader_hide_menu); - view_dispatcher_switch_to_view( - loader_instance->view_dispatcher, LoaderMenuViewSettings); - view_dispatcher_run(loader_instance->view_dispatcher); - view_set_previous_callback( - submenu_get_view(loader_instance->settings_menu), loader_back_to_primary_menu); + LoaderMessage message; + while(true) { + if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { + switch(message.type) { + case LoaderMessageTypeStartByName: + message.status_value->value = + loader_do_start_by_name(loader, message.start.name, message.start.args); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeShowMenu: + loader_do_menu_show(loader, false); + break; + case LoaderMessageTypeShowSettings: + loader_do_menu_show(loader, true); + break; + case LoaderMessageTypeMenuClosed: + loader_do_menu_closed(loader); + break; + case LoaderMessageTypeIsLocked: + message.bool_value->value = loader_do_is_locked(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeAppClosed: + loader_do_app_closed(loader); + break; + case LoaderMessageTypeLock: + message.bool_value->value = loader_do_lock(loader); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeUnlock: + loader_do_unlock(loader); + } } } - furi_record_destroy(RECORD_LOADER); - loader_free(loader_instance); - return 0; } - -FuriPubSub* loader_get_pubsub(Loader* instance) { - return instance->pubsub; -} diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 58516b339..e8f1fd64e 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,7 +1,5 @@ #pragma once - -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -45,16 +43,13 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(const Loader* instance); +bool loader_is_locked(Loader* instance); /** Show primary loader */ -void loader_show_menu(); +void loader_show_menu(Loader* instance); /** Show settings menu */ -void loader_show_settings(); - -/** Show primary loader */ -void loader_update_menu(); +void loader_show_settings(Loader* loader); /** Show primary loader */ FuriPubSub* loader_get_pubsub(Loader* instance); diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c new file mode 100644 index 000000000..2d4602215 --- /dev/null +++ b/applications/services/loader/loader_cli.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include "loader.h" + +static void loader_cli_print_usage() { + printf("Usage:\r\n"); + printf("loader \r\n"); + printf("Cmd list:\r\n"); + printf("\tlist\t - List available applications\r\n"); + printf("\topen \t - Open application by name\r\n"); + printf("\tinfo\t - Show loader state\r\n"); +} + +static void loader_cli_list() { + printf("Applications:\r\n"); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } + printf("Settings:\r\n"); + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + printf("\t%s\r\n", FLIPPER_SETTINGS_APPS[i].name); + } +} + +static void loader_cli_info(Loader* loader) { + if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + // TODO: print application name ??? + printf("Application is running\r\n"); + } +} + +static void loader_cli_open(FuriString* args, Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + do { + if(!args_read_probably_quoted_string_and_trim(args, app_name)) { + printf("No application provided\r\n"); + break; + } + furi_string_trim(args); + + const char* args_str = furi_string_get_cstr(args); + if(strlen(args_str) == 0) { + args_str = NULL; + } + + const char* app_name_str = furi_string_get_cstr(app_name); + + LoaderStatus status = loader_start(loader, app_name_str, args_str); + + switch(status) { + case LoaderStatusOk: + break; + case LoaderStatusErrorAppStarted: + printf("Can't start, application is running"); + break; + case LoaderStatusErrorUnknownApp: + printf("%s doesn't exists\r\n", app_name_str); + break; + case LoaderStatusErrorInternal: + printf("Internal error\r\n"); + break; + } + } while(false); + + furi_string_free(app_name); +} + +static void loader_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + UNUSED(context); + Loader* loader = furi_record_open(RECORD_LOADER); + + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + loader_cli_print_usage(); + break; + } + + if(furi_string_cmp_str(cmd, "list") == 0) { + loader_cli_list(); + break; + } + + if(furi_string_cmp_str(cmd, "open") == 0) { + loader_cli_open(args, loader); + break; + } + + if(furi_string_cmp_str(cmd, "info") == 0) { + loader_cli_info(loader); + break; + } + + loader_cli_print_usage(); + } while(false); + + furi_string_free(cmd); + furi_record_close(RECORD_LOADER); +} + +void loader_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, RECORD_LOADER, CliCommandFlagParallelSafe, loader_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(loader_cli); +#endif +} \ No newline at end of file diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 00028cd6b..4a1477a7b 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,39 +1,57 @@ -#include "loader.h" - +#pragma once #include -#include -#include -#include -#include +#include +#include "loader.h" +#include "loader_menu.h" -#include - -#include -#include - -#include -#include +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData; struct Loader { - FuriThreadId loader_thread; - - const FlipperApplication* application; - FuriThread* application_thread; - char* application_arguments; - - Cli* cli; - Gui* gui; - - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - volatile uint8_t lock_count; - FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu* loader_menu; + LoaderAppData app; }; typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; + LoaderMessageTypeStartByName, + LoaderMessageTypeAppClosed, + LoaderMessageTypeShowMenu, + LoaderMessageTypeMenuClosed, + LoaderMessageTypeLock, + LoaderMessageTypeUnlock, + LoaderMessageTypeIsLocked, + LoaderMessageTypeShowSettings, +} LoaderMessageType; + +typedef struct { + const char* name; + const char* args; +} LoaderMessageStartByName; + +typedef struct { + LoaderStatus value; +} LoaderMessageLoaderStatusResult; + +typedef struct { + bool value; +} LoaderMessageBoolResult; + +typedef struct { + FuriApiLock api_lock; + LoaderMessageType type; + + union { + LoaderMessageStartByName start; + }; + + union { + LoaderMessageLoaderStatusResult* status_value; + LoaderMessageBoolResult* bool_value; + }; +} LoaderMessage; diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c new file mode 100644 index 000000000..1391394e5 --- /dev/null +++ b/applications/services/loader/loader_menu.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "applications/main/fap_loader/fap_loader_app.h" +#include + +#include "loader_menu.h" + +#define TAG "LoaderMenu" + +struct LoaderMenu { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; + bool settings; + + void (*closed_callback)(void*); + void* closed_callback_context; + + void (*click_callback)(const char*, bool, void*); + void* click_callback_context; + + FuriThread* thread; +}; + +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +static int32_t loader_menu_thread(void* p); + +LoaderMenu* loader_menu_alloc() { + LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); + loader_menu->gui = furi_record_open(RECORD_GUI); + loader_menu->view_dispatcher = view_dispatcher_alloc(); + loader_menu->primary_menu = menu_alloc(); + loader_menu->settings_menu = submenu_alloc(); + loader_menu->thread = NULL; + return loader_menu; +} + +void loader_menu_free(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + // check if thread is running + furi_assert(!loader_menu->thread); + + submenu_free(loader_menu->settings_menu); + menu_free(loader_menu->primary_menu); + view_dispatcher_free(loader_menu->view_dispatcher); + furi_record_close(RECORD_GUI); + free(loader_menu); +} + +void loader_menu_start(LoaderMenu* loader_menu, bool settings) { + furi_assert(loader_menu); + furi_assert(!loader_menu->thread); + loader_menu->settings = settings; + loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); + furi_thread_start(loader_menu->thread); +} + +void loader_menu_stop(LoaderMenu* loader_menu) { + furi_assert(loader_menu); + furi_assert(loader_menu->thread); + view_dispatcher_stop(loader_menu->view_dispatcher); + furi_thread_join(loader_menu->thread); + furi_thread_free(loader_menu->thread); + loader_menu->thread = NULL; +} + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context) { + loader_menu->closed_callback = callback; + loader_menu->closed_callback_context = context; +} + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, bool, void*), + void* context) { + loader_menu->click_callback = callback; + loader_menu->click_callback_context = context; +} + +static void loader_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, false, loader_menu->click_callback_context); + } +} + +static void loader_menu_external_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* path = (const char*)index; + if(loader_menu->click_callback) { + loader_menu->click_callback(path, true, loader_menu->click_callback_context); + } +} + +static void loader_menu_settings_menu_callback(void* context, uint32_t index) { + LoaderMenu* loader_menu = context; + const char* name = FLIPPER_SETTINGS_APPS[index].name; + if(loader_menu->click_callback) { + loader_menu->click_callback(name, false, loader_menu->click_callback_context); + } +} + +static void loader_menu_switch_to_settings(void* context, uint32_t index) { + UNUSED(index); + LoaderMenu* loader_menu = context; + view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); +} + +static uint32_t loader_menu_switch_to_primary(void* context) { + UNUSED(context); + return LoaderMenuViewPrimary; +} + +static uint32_t loader_menu_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +bool loader_menu_load_fap_meta( + Storage* storage, + FuriString* path, + FuriString* name, + const Icon** icon) { + *icon = NULL; + uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); + if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { + free(icon_buf); + icon_buf = NULL; + return false; + } + *icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN((*icon)->frame_count, 1); + FURI_CONST_ASSIGN((*icon)->frame_rate, 0); + FURI_CONST_ASSIGN((*icon)->width, 10); + FURI_CONST_ASSIGN((*icon)->height, 10); + FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); + FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + return true; +} + +static void loader_menu_build_menu(LoaderMenu* loader_menu) { + size_t i; + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_menu->primary_menu, + FLIPPER_APPS[i].name, + FLIPPER_APPS[i].icon, + i, + loader_menu_callback, + (void*)loader_menu); + } + menu_add_item( + loader_menu->primary_menu, + "Settings", + &A_Settings_14, + i++, + loader_menu_switch_to_settings, + loader_menu); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* path = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + Stream* stream = file_stream_alloc(storage); + if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, path)) { + furi_string_replace_all(path, "\r", ""); + furi_string_replace_all(path, "\n", ""); + const Icon* icon; + if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; + menu_add_item( + loader_menu->primary_menu, + strdup(furi_string_get_cstr(name)), + icon, + (uint32_t)strdup(furi_string_get_cstr(path)), + loader_menu_external_callback, + (void*)loader_menu); + } + } + file_stream_close(stream); + stream_free(stream); + furi_string_free(name); + furi_string_free(path); + furi_record_close(RECORD_STORAGE); +}; + +static void loader_menu_build_submenu(LoaderMenu* loader_menu) { + for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { + submenu_add_item( + loader_menu->settings_menu, + FLIPPER_SETTINGS_APPS[i].name, + i, + loader_menu_settings_menu_callback, + loader_menu); + } +} + +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + if(!loader_menu->settings) loader_menu_build_menu(loader_menu); + loader_menu_build_submenu(loader_menu); + + view_dispatcher_attach_to_gui( + loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + + // Primary menu + if(!loader_menu->settings) { + View* primary_view = menu_get_view(loader_menu->primary_menu); + view_set_context(primary_view, loader_menu->primary_menu); + view_set_previous_callback(primary_view, loader_menu_exit); + view_dispatcher_add_view( + loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + } + + // Settings menu + View* settings_view = submenu_get_view(loader_menu->settings_menu); + view_set_context(settings_view, loader_menu->settings_menu); + view_set_previous_callback( + settings_view, loader_menu->settings ? loader_menu_exit : loader_menu_switch_to_primary); + view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + + view_dispatcher_enable_queue(loader_menu->view_dispatcher); + view_dispatcher_switch_to_view( + loader_menu->view_dispatcher, + loader_menu->settings ? LoaderMenuViewSettings : LoaderMenuViewPrimary); + + // run view dispatcher + view_dispatcher_run(loader_menu->view_dispatcher); + + if(!loader_menu->settings) + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + + if(loader_menu->closed_callback) { + loader_menu->closed_callback(loader_menu->closed_callback_context); + } + + return 0; +} diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h new file mode 100644 index 000000000..db39834da --- /dev/null +++ b/applications/services/loader/loader_menu.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderMenu LoaderMenu; + +LoaderMenu* loader_menu_alloc(); + +void loader_menu_free(LoaderMenu* loader_menu); + +void loader_menu_start(LoaderMenu* loader_menu, bool settings); + +void loader_menu_stop(LoaderMenu* loader_menu); + +void loader_menu_set_closed_callback( + LoaderMenu* loader_menu, + void (*callback)(void*), + void* context); + +void loader_menu_set_click_callback( + LoaderMenu* loader_menu, + void (*callback)(const char*, bool, void*), + void* context); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 62428d79d..879754fd5 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { return 0; } -static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { - furi_assert(context); - +static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); RpcSession* session = (RpcSession*)context; + for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { + if(rpc_systems[i].free) { + (rpc_systems[i].free)(session->system_contexts[i]); + } + } + free(session->system_contexts); + free(session->decoded_message); + RpcHandlerDict_clear(session->handlers); + furi_stream_buffer_free(session->stream); + + furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); + if(session->terminated_callback) { + session->terminated_callback(session->context); + } + furi_mutex_release(session->callbacks_mutex); + + furi_mutex_free(session->callbacks_mutex); + furi_thread_join(session->thread); + furi_thread_free(session->thread); + free(session); +} + +static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { if(thread_state == FuriThreadStateStopped) { - for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { - if(rpc_systems[i].free) { - rpc_systems[i].free(session->system_contexts[i]); - } - } - free(session->system_contexts); - free(session->decoded_message); - RpcHandlerDict_clear(session->handlers); - furi_stream_buffer_free(session->stream); - - furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); - if(session->terminated_callback) { - session->terminated_callback(session->context); - } - furi_mutex_release(session->callbacks_mutex); - - furi_mutex_free(session->callbacks_mutex); - furi_thread_free(session->thread); - free(session); + furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); } } @@ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); furi_thread_set_state_context(session->thread, session); - furi_thread_set_state_callback(session->thread, rpc_session_free_callback); + furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); furi_thread_start(session->thread); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ffc3da4bc..bf474bc9d 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -803,6 +803,7 @@ void storage_file_free(File* file) { } FuriPubSub* storage_get_pubsub(Storage* storage) { + furi_assert(storage); return storage->pubsub; } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index d802d6e9f..15a355dc2 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { file->internal_error_id = f_close(file_data); file->error_id = storage_ext_parse_error(file->internal_error_id); free(file_data); + storage_set_storage_file_data(file, NULL, storage); return (file->error_id == FSE_OK); } diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 2f61ceb2c..fd6be1685 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -212,7 +212,9 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { (uint32_t)(info->voltage_vbus), (uint32_t)(info->voltage_vbus * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf(header, sizeof(header), "%s", "Consumption is"); snprintf( value, diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 828c518d6..9ffb0d22b 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, current); - } else if(current < 0) { + } else if(current < -5) { + // Often gauge reports anything in the range 1~5ma as 5ma + // That brings confusion, so we'll treat it as Napping snprintf( emote, sizeof(emote), diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 655541be5..68a895004 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -43,7 +43,6 @@ static void debug_changed(VariableItem* item) { } else { furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); } - loader_update_menu(); } const char* const heap_trace_mode_text[] = { diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 2bf6dab26..659c431f7 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { updater_cli_help(args); } -static int32_t updater_spawner_thread_worker(void* arg) { +static void updater_start_app(void* context, uint32_t arg) { + UNUSED(context); UNUSED(arg); - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); - furi_record_close(RECORD_LOADER); - return 0; -} -static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { - FuriThread* thread = context; - if(state == FuriThreadStateStopped) { - furi_thread_free(thread); - } -} - -static void updater_start_app() { FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { return; @@ -110,11 +98,9 @@ static void updater_start_app() { * inside loader process, at startup. * So, accessing its record would cause a deadlock */ - FuriThread* thread = - furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); - furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); - furi_thread_set_state_context(thread, thread); - furi_thread_start(thread); + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start(loader, "UpdaterApp", NULL); + furi_record_close(RECORD_LOADER); } void updater_on_system_start() { @@ -126,7 +112,7 @@ void updater_on_system_start() { UNUSED(updater_cli_ep); #endif #ifndef FURI_RAM_EXEC - updater_start_app(); + furi_timer_pending_callback(updater_start_app, NULL, 0); #else UNUSED(updater_start_app); #endif diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 63024ced9..5d2477464 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); // Format LFS before restoring backup on next boot furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); - +#ifdef FURI_NDEBUG + // Production + furi_hal_rtc_set_log_level(FuriLogLevelDefault); + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); +#endif update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); success = true; } while(false); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f2622c340..a0ae040a5 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,+,23.3,, +Version,+,26.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -1376,12 +1379,11 @@ Function,-,ldiv,ldiv_t,"long, long" Function,-,llabs,long long,long long Function,-,lldiv,lldiv_t,"long long, long long" Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, +Function,+,loader_show_menu,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7878e5c68..ba82545e3 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,23.0,, +Version,+,26.0,, Header,+,applications/main/fap_loader/fap_loader_app.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1171,6 +1171,8 @@ Function,+,furi_hal_console_puts,void,const char* Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" +Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp Function,+,furi_hal_cortex_delay_us,void,uint32_t Function,-,furi_hal_cortex_init_early,void, Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, @@ -1683,7 +1685,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1692,6 +1694,7 @@ Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -1921,13 +1924,12 @@ 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,const Loader* +Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* -Function,+,loader_show_menu,void, -Function,+,loader_show_settings,void, +Function,+,loader_show_menu,void,Loader* +Function,+,loader_show_settings,void,Loader* Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* -Function,+,loader_update_menu,void, Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* Function,+,loading_get_view,View*,Loading* diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index d0bce5038..3fbe384e3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,11 +1,12 @@ #include +#include #include #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) void furi_hal_cortex_init_early() { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0U; @@ -38,4 +39,71 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer) { void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { while(!furi_hal_cortex_timer_is_expired(cortex_timer)) ; -} \ No newline at end of file +} + +// Duck ST +#undef COMP0 +#undef COMP1 +#undef COMP2 +#undef COMP3 + +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size) { + uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); + + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = value; + (DWT->MASK0) = mask; + (DWT->FUNCTION0) = function_reg; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = value; + (DWT->MASK1) = mask; + (DWT->FUNCTION1) = function_reg; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = value; + (DWT->MASK2) = mask; + (DWT->FUNCTION2) = function_reg; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = value; + (DWT->MASK3) = mask; + (DWT->FUNCTION3) = function_reg; + break; + default: + furi_crash("Invalid parameter"); + } +} + +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { + switch(comp) { + case FuriHalCortexComp0: + (DWT->COMP0) = 0; + (DWT->MASK0) = 0; + (DWT->FUNCTION0) = 0; + break; + case FuriHalCortexComp1: + (DWT->COMP1) = 0; + (DWT->MASK1) = 0; + (DWT->FUNCTION1) = 0; + break; + case FuriHalCortexComp2: + (DWT->COMP2) = 0; + (DWT->MASK2) = 0; + (DWT->FUNCTION2) = 0; + break; + case FuriHalCortexComp3: + (DWT->COMP3) = 0; + (DWT->MASK3) = 0; + (DWT->FUNCTION3) = 0; + break; + default: + furi_crash("Invalid parameter"); + } +} diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/firmware/targets/furi_hal_include/furi_hal_cortex.h index 91596ffe3..ebabbabfd 100644 --- a/firmware/targets/furi_hal_include/furi_hal_cortex.h +++ b/firmware/targets/furi_hal_include/furi_hal_cortex.h @@ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); */ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); +typedef enum { + FuriHalCortexComp0, + FuriHalCortexComp1, + FuriHalCortexComp2, + FuriHalCortexComp3, +} FuriHalCortexComp; + +typedef enum { + FuriHalCortexCompSizeWord = 0b10, + FuriHalCortexCompSizeHalfWord = 0b01, + FuriHalCortexCompSizeByte = 0b00, +} FuriHalCortexCompSize; + +typedef enum { + FuriHalCortexCompFunctionPC = 0b100, + FuriHalCortexCompFunctionRead = 0b101, + FuriHalCortexCompFunctionWrite = 0b110, + FuriHalCortexCompFunctionReadWrite = 0b110, +} FuriHalCortexCompFunction; + +/** Enable DWT comparator + * + * Allows to programmatically set instruction/data breakpoints. + * + * More details on how it works can be found in armv7m official documentation: + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators + * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn + * + * @param[in] comp The Comparator + * @param[in] function The Comparator Function to use + * @param[in] value The value + * @param[in] mask The mask + * @param[in] size The size + */ +void furi_hal_cortex_comp_enable( + FuriHalCortexComp comp, + FuriHalCortexCompFunction function, + uint32_t value, + uint32_t mask, + FuriHalCortexCompSize size); + +/** Reset DWT comparator + * + * @param[in] comp The Comparator + */ +void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index d78070d61..facbcb411 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( void furi_thread_free(FuriThread* thread) { furi_assert(thread); - furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); - if(thread->appid) free((void*)thread->appid); + // Ensure that use join before free + furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(thread->task_handle == NULL); + + if(thread->name) free(thread->name); + if(thread->appid) free(thread->appid); furi_string_free(thread->output.buffer); free(thread); @@ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->name) free((void*)thread->name); + if(thread->name) free(thread->name); thread->name = name ? strdup(name) : NULL; } void furi_thread_set_appid(FuriThread* thread, const char* appid) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->appid) free((void*)thread->appid); + if(thread->appid) free(thread->appid); thread->appid = appid ? strdup(appid) : NULL; } @@ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { if(thread) { // clear thread local storage vTaskSetThreadLocalStoragePointer(task, 0, NULL); - + furi_assert(thread->task_handle == task); thread->task_handle = NULL; } } @@ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { FuriThread* furi_thread_get_current() { FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); - furi_assert(thread != NULL); return thread; } @@ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; - - return true; } FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); return thread->output.write_callback; } size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); - + furi_assert(thread); if(size == 0 || data == NULL) { return __furi_thread_stdout_flush(thread); } else { @@ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { } int32_t furi_thread_stdout_flush() { - return __furi_thread_stdout_flush(furi_thread_get_current()); + FuriThread* thread = furi_thread_get_current(); + furi_assert(thread); + return __furi_thread_stdout_flush(thread); } void furi_thread_suspend(FuriThreadId thread_id) { diff --git a/furi/core/thread.h b/furi/core/thread.h index b11a225b5..022894ee8 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); /** Get FuriThread instance for current thread * - * @return FuriThread* + * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi */ FuriThread* furi_thread_get_current(); @@ -288,12 +288,10 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); /** Set STDOUT callback for thread - * + * * @param callback callback or NULL to clear - * - * @return true on success, otherwise fail */ -bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); /** Write data to buffered STDOUT * diff --git a/furi/core/timer.c b/furi/core/timer.c index 4b6ccecba..7743ffe70 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { /* Return 0: not running, 1: running */ return (uint32_t)xTimerIsTimerActive(hTimer); } + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { + BaseType_t ret = pdFAIL; + if(furi_kernel_is_irq_or_masked()) { + ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); + } else { + ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); + } + furi_check(ret == pdPASS); +} \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index e79c1868d..3f43de5fd 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); + +void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); + #ifdef __cplusplus } #endif From 24dd4336c4973e95ab0eabbf8954c2ec43463deb Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 02:53:21 +0100 Subject: [PATCH 137/216] Dont reload ext main apps data on each menu open --- applications/services/loader/loader.c | 54 +++++++++++++++- applications/services/loader/loader.h | 1 + .../services/loader/loader_extmainapp.h | 12 ++++ applications/services/loader/loader_i.h | 1 + applications/services/loader/loader_menu.c | 64 ++++--------------- applications/services/loader/loader_menu.h | 3 +- 6 files changed, 82 insertions(+), 53 deletions(-) create mode 100644 applications/services/loader/loader_extmainapp.h diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index b9f47dcdd..12651eba7 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -3,6 +3,11 @@ #include "loader_menu.h" #include #include +#include +#include +#include +#include "applications/main/fap_loader/fap_loader_app.h" +#include #define TAG "Loader" #define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF @@ -107,6 +112,28 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con } } +bool loader_menu_load_fap_meta( + Storage* storage, + FuriString* path, + FuriString* name, + const Icon** icon) { + *icon = NULL; + uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); + if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { + free(icon_buf); + icon_buf = NULL; + return false; + } + *icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN((*icon)->frame_count, 1); + FURI_CONST_ASSIGN((*icon)->frame_rate, 0); + FURI_CONST_ASSIGN((*icon)->width, 10); + FURI_CONST_ASSIGN((*icon)->height, 10); + FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); + FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); + return true; +} + // implementation static Loader* loader_alloc() { @@ -118,6 +145,31 @@ static Loader* loader_alloc() { loader->app.name = NULL; loader->app.thread = NULL; loader->app.insomniac = false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* path = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + Stream* stream = file_stream_alloc(storage); + ExtMainAppList_init(loader->ext_main_apps); + if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + while(stream_read_line(stream, path)) { + furi_string_replace_all(path, "\r", ""); + furi_string_replace_all(path, "\n", ""); + const Icon* icon; + if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; + ExtMainAppList_push_back( + loader->ext_main_apps, + (ExtMainApp){ + .name = strdup(furi_string_get_cstr(name)), + .path = strdup(furi_string_get_cstr(path)), + .icon = icon}); + } + } + file_stream_close(stream); + stream_free(stream); + furi_string_free(name); + furi_string_free(path); + furi_record_close(RECORD_STORAGE); return loader; } @@ -204,7 +256,7 @@ static void loader_do_menu_show(Loader* loader, bool settings) { loader->loader_menu = loader_menu_alloc(); loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); - loader_menu_start(loader->loader_menu, settings); + loader_menu_start(loader->loader_menu, settings, &loader->ext_main_apps); } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index e8f1fd64e..b31bb1bdd 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -1,5 +1,6 @@ #pragma once #include +#include "loader_extmainapp.h" #ifdef __cplusplus extern "C" { diff --git a/applications/services/loader/loader_extmainapp.h b/applications/services/loader/loader_extmainapp.h new file mode 100644 index 000000000..2e10b16a3 --- /dev/null +++ b/applications/services/loader/loader_extmainapp.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +typedef struct { + const char* name; + const char* path; + const Icon* icon; +} ExtMainApp; + +LIST_DEF(ExtMainAppList, ExtMainApp, M_POD_OPLIST) diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 4a1477a7b..6887b4b50 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -16,6 +16,7 @@ struct Loader { FuriMessageQueue* queue; LoaderMenu* loader_menu; LoaderAppData app; + ExtMainAppList_t ext_main_apps; }; typedef enum { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 1391394e5..c4e14038c 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -4,11 +4,6 @@ #include #include #include -#include -#include -#include -#include "applications/main/fap_loader/fap_loader_app.h" -#include #include "loader_menu.h" @@ -19,7 +14,9 @@ struct LoaderMenu { ViewDispatcher* view_dispatcher; Menu* primary_menu; Submenu* settings_menu; + bool settings; + ExtMainAppList_t* ext_main_apps; void (*closed_callback)(void*); void* closed_callback_context; @@ -59,10 +56,11 @@ void loader_menu_free(LoaderMenu* loader_menu) { free(loader_menu); } -void loader_menu_start(LoaderMenu* loader_menu, bool settings) { +void loader_menu_start(LoaderMenu* loader_menu, bool settings, ExtMainAppList_t* ext_main_apps) { furi_assert(loader_menu); furi_assert(!loader_menu->thread); loader_menu->settings = settings; + loader_menu->ext_main_apps = ext_main_apps; loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); furi_thread_start(loader_menu->thread); } @@ -132,28 +130,6 @@ static uint32_t loader_menu_exit(void* context) { return VIEW_NONE; } -bool loader_menu_load_fap_meta( - Storage* storage, - FuriString* path, - FuriString* name, - const Icon** icon) { - *icon = NULL; - uint8_t* icon_buf = malloc(CUSTOM_ICON_MAX_SIZE); - if(!fap_loader_load_name_and_icon(path, storage, &icon_buf, name)) { - free(icon_buf); - icon_buf = NULL; - return false; - } - *icon = malloc(sizeof(Icon)); - FURI_CONST_ASSIGN((*icon)->frame_count, 1); - FURI_CONST_ASSIGN((*icon)->frame_rate, 0); - FURI_CONST_ASSIGN((*icon)->width, 10); - FURI_CONST_ASSIGN((*icon)->height, 10); - FURI_CONST_ASSIGN_PTR((*icon)->frames, malloc(sizeof(const uint8_t*))); - FURI_CONST_ASSIGN_PTR((*icon)->frames[0], icon_buf); - return true; -} - static void loader_menu_build_menu(LoaderMenu* loader_menu) { size_t i; for(i = 0; i < FLIPPER_APPS_COUNT; i++) { @@ -173,30 +149,16 @@ static void loader_menu_build_menu(LoaderMenu* loader_menu) { loader_menu_switch_to_settings, loader_menu); - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* path = furi_string_alloc(); - FuriString* name = furi_string_alloc(); - Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - while(stream_read_line(stream, path)) { - furi_string_replace_all(path, "\r", ""); - furi_string_replace_all(path, "\n", ""); - const Icon* icon; - if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; - menu_add_item( - loader_menu->primary_menu, - strdup(furi_string_get_cstr(name)), - icon, - (uint32_t)strdup(furi_string_get_cstr(path)), - loader_menu_external_callback, - (void*)loader_menu); - } + for(i = 0; i < ExtMainAppList_size(*loader_menu->ext_main_apps); i++) { + const ExtMainApp* app = ExtMainAppList_get(*loader_menu->ext_main_apps, i); + menu_add_item( + loader_menu->primary_menu, + app->name, + app->icon, + (uint32_t)app->path, + loader_menu_external_callback, + (void*)loader_menu); } - file_stream_close(stream); - stream_free(stream); - furi_string_free(name); - furi_string_free(path); - furi_record_close(RECORD_STORAGE); }; static void loader_menu_build_submenu(LoaderMenu* loader_menu) { diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h index db39834da..f4188b733 100644 --- a/applications/services/loader/loader_menu.h +++ b/applications/services/loader/loader_menu.h @@ -1,5 +1,6 @@ #pragma once #include +#include "loader_extmainapp.h" #ifdef __cplusplus extern "C" { @@ -11,7 +12,7 @@ LoaderMenu* loader_menu_alloc(); void loader_menu_free(LoaderMenu* loader_menu); -void loader_menu_start(LoaderMenu* loader_menu, bool settings); +void loader_menu_start(LoaderMenu* loader_menu, bool settings, ExtMainAppList_t* ext_main_apps); void loader_menu_stop(LoaderMenu* loader_menu); From cb8c77ee2c3ee1bf48f33c9107ae4b6daa3808ea Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 16:36:15 +0300 Subject: [PATCH 138/216] SubGhz: remove direct reading --- .../subghz/scenes/subghz_scene_read_raw.c | 101 ++++++------------ .../subghz/scenes/subghz_scene_receiver.c | 22 ++-- .../scenes/subghz_scene_receiver_info.c | 68 +++++------- .../main/subghz/scenes/subghz_scene_rpc.c | 12 +-- .../subghz/scenes/subghz_scene_transmitter.c | 36 +++---- applications/main/subghz/subghz_i.c | 25 +++++ applications/main/subghz/subghz_i.h | 8 +- 7 files changed, 116 insertions(+), 156 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 35b3fa58e..33cd2ebb6 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -127,16 +127,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz); //Stop save file subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -171,16 +162,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWTXRXStop: - //Stop TX - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - //Stop RX - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz); subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -229,33 +211,27 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; - subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusIDLE, - "", - subghz_threshold_rssi_get(subghz->threshold_rssi)); - } else { - if(scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneSaved) || - !scene_manager_has_previous_scene( - subghz->scene_manager, SubGhzSceneStart)) { - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } - // set callback end tx - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - subghz->txrx->transmitter), - subghz_scene_read_raw_callback_end_tx, - subghz); - subghz->state_notifications = SubGhzNotificationStateTx; + + subghz_txrx_stop(subghz); + if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz_threshold_rssi_get(subghz->threshold_rssi)); + } else { + if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) || + !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) { + DOLPHIN_DEED(DolphinDeedSubGhzSend); } + // set callback end tx + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( + subghz->txrx->transmitter), + subghz_scene_read_raw_callback_end_tx, + subghz); + subghz->state_notifications = SubGhzNotificationStateTx; } } else { if(!scene_manager_search_and_switch_to_previous_scene( @@ -269,21 +245,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_speaker_unmute(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz); subghz_read_raw_stop_send(subghz->subghz_read_raw); consumed = true; break; case SubGhzCustomEventViewReadRAWIDLE: - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; - + subghz_txrx_stop(subghz); size_t spl_count = subghz_protocol_raw_get_sample_write( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -318,15 +286,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { RAW_FILE_NAME, subghz->txrx->preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_txrx_stop(subghz); + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); + subghz->state_notifications = SubGhzNotificationStateRx; subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } else { @@ -389,10 +355,7 @@ void subghz_scene_read_raw_on_exit(void* context) { SubGhz* subghz = context; //Stop CC1101 - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - }; + subghz_txrx_stop(subghz); subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 18008674d..7dd7d3993 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -190,17 +190,12 @@ void subghz_scene_receiver_on_enter(void* context) { } subghz->state_notifications = SubGhzNotificationStateRx; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } - if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || - (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_txrx_stop(subghz); + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it @@ -219,10 +214,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz); subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index a108132c0..13095b081 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -125,36 +125,29 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { subghz->txrx->hopper_state = SubGhzHopperStatePause; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - } + + subghz_txrx_stop(subghz); + if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || - subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { - if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunning; - } - subghz->state_notifications = SubGhzNotificationStateRx; - } else { - subghz->state_notifications = SubGhzNotificationStateTx; + + if(!subghz_tx_start( + subghz, + subghz_history_get_raw_data( + subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { + subghz_txrx_stop(subghz); + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } + subghz->state_notifications = SubGhzNotificationStateRx; + } else { + subghz->state_notifications = SubGhzNotificationStateTx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { @@ -164,17 +157,14 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - } + subghz_txrx_stop(subghz); if(!subghz->in_decoder_scene) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { subghz->txrx->hopper_state = SubGhzHopperStateRunning; } @@ -185,10 +175,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; subghz->txrx->hopper_state = SubGhzHopperStateOFF; - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - subghz_sleep(subghz); - } + + subghz_txrx_stop(subghz); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 8140f69a2..4d6806a9d 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -42,7 +42,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) && + if((subghz_txrx_get_state(subghz) == SubGhzTxRxStateSleep) && (state == SubGhzRpcStateLoaded)) { result = subghz_tx_start(subghz, subghz->txrx->fff_data); if(result) subghz_blink_start(subghz); @@ -56,10 +56,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + if(subghz_txrx_get_state(subghz) == SubGhzTxRxStateTx) { + subghz_txrx_stop(subghz); subghz_blink_stop(subghz); - subghz_tx_stop(subghz); - subghz_sleep(subghz); result = true; } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); @@ -97,9 +96,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); + if(subghz_txrx_get_state(subghz) == SubGhzTxRxStateTx) { + subghz_txrx_stop(subghz); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index d1fafd8ff..ed4088ec5 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -70,40 +70,28 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - 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)) { - subghz->state_notifications = SubGhzNotificationStateTx; - subghz_scene_transmitter_update_data_show(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzSend); - } + subghz_txrx_stop(subghz); + if(subghz_tx_start(subghz, subghz->txrx->fff_data)) { + subghz->state_notifications = SubGhzNotificationStateTx; + subghz_scene_transmitter_update_data_show(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzSend); } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + subghz_txrx_stop(subghz); if(subghz_custom_btn_get() != 0) { subghz_custom_btn_set(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); + subghz_txrx_stop(subghz); + + if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } - 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); + + subghz_txrx_stop(subghz); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } return true; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 77eba42fb..bf9823cea 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -228,6 +228,31 @@ void subghz_tx_stop(SubGhz* subghz) { notification_message(subghz->notifications, &sequence_reset_red); } +void subghz_txrx_stop(SubGhz* subghz) { + furi_assert(subghz); + + switch(subghz->txrx->txrx_state) { + case SubGhzTxRxStateTx: + subghz_tx_stop(subghz); + subghz_speaker_unmute(subghz); + subghz_sleep(subghz); + break; + case SubGhzTxRxStateRx: + subghz_rx_end(subghz); + subghz_speaker_mute(subghz); + subghz_sleep(subghz); + break; + + default: + break; + } +} + +SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz) { + furi_assert(subghz); + return subghz->txrx->txrx_state; +} + void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 9c58af7bb..5969d85cb 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -72,12 +72,15 @@ struct SubGhzTxRx { SubGhzRadioPreset* preset; SubGhzHistory* history; uint16_t idx_menu_chosen; + uint8_t hopper_timeout; uint8_t hopper_idx_frequency; - SubGhzTxRxState txrx_state; SubGhzHopperState hopper_state; SubGhzSpeakerState speaker_state; + + SubGhzTxRxState txrx_state; + bool ignore_starline; bool ignore_auto_alarms; bool ignore_magellan; @@ -175,5 +178,8 @@ void subghz_speaker_off(SubGhz* subghz); void subghz_speaker_mute(SubGhz* subghz); void subghz_speaker_unmute(SubGhz* subghz); +void subghz_txrx_stop(SubGhz* subghz); +SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz); + extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; From c98e76f31e52d526b9b4ba42cc1135b907639d29 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 17:02:32 +0300 Subject: [PATCH 139/216] SubGhz: remove direct reading (hopper_state) --- .../subghz/scenes/subghz_scene_receiver.c | 4 ++-- .../scenes/subghz_scene_receiver_config.c | 6 ++--- .../scenes/subghz_scene_receiver_info.c | 16 ++++--------- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_i.c | 24 +++++++++++++++++++ applications/main/subghz/subghz_i.h | 4 ++++ 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 7dd7d3993..8de7870a8 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -215,7 +215,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz); - subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); @@ -269,7 +269,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + if(subghz_hopper_get_state(subghz) != SubGhzHopperStateOFF) { subghz_hopper_update(subghz); subghz_scene_receiver_update_statusbar(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index bd9780428..ef8ffc9bd 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -143,7 +143,7 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + if(subghz_hopper_get_state(subghz) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; snprintf( text_buf, @@ -209,7 +209,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) subghz_setting_get_frequency_default_index(subghz->setting)); } - subghz->txrx->hopper_state = hopping_value[index]; + subghz_hopper_set_state(subghz, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -317,7 +317,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + subghz_hopper_get_state(subghz), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 13095b081..dd637c1eb 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -122,9 +122,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { //CC1101 Stop RX -> Start TX - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { - subghz->txrx->hopper_state = SubGhzHopperStatePause; - } + subghz_subghz_hopper_set_pause(subghz); subghz_txrx_stop(subghz); @@ -142,9 +140,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_setting_get_preset_data_by_name( subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); subghz_rx(subghz, subghz->txrx->preset->frequency); - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunning; - } + subghz_hopper_remove_pause(subghz); subghz->state_notifications = SubGhzNotificationStateRx; } else { subghz->state_notifications = SubGhzNotificationStateTx; @@ -165,16 +161,14 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); subghz_rx(subghz, subghz->txrx->preset->frequency); - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunning; - } + subghz_hopper_remove_pause(subghz); subghz->state_notifications = SubGhzNotificationStateRx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); subghz_txrx_stop(subghz); if(!subghz_scene_receiver_info_update_parser(subghz)) { @@ -193,7 +187,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + if(subghz_hopper_get_state(subghz) != SubGhzHopperStateOFF) { subghz_hopper_update(subghz); } switch(subghz->state_notifications) { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 4bbdba6c5..7e35346b8 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -271,7 +271,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); } subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->debug_pin_state = false; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index bf9823cea..194b404db 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -629,6 +629,30 @@ void subghz_hopper_update(SubGhz* subghz) { } } +SubGhzHopperState subghz_hopper_get_state(SubGhz* subghz) { + furi_assert(subghz); + return subghz->txrx->hopper_state; +} + +void subghz_hopper_set_state(SubGhz* subghz, SubGhzHopperState state) { + furi_assert(subghz); + subghz->txrx->hopper_state = state; +} + +void subghz_hopper_remove_pause(SubGhz* subghz) { + furi_assert(subghz); + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { + subghz->txrx->hopper_state = SubGhzHopperStateRunning; + } +} + +void subghz_subghz_hopper_set_pause(SubGhz* subghz) { + furi_assert(subghz); + if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + subghz->txrx->hopper_state = SubGhzHopperStatePause; + } +} + void subghz_speaker_on(SubGhz* subghz) { if(subghz->txrx->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 5969d85cb..f772c388c 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -180,6 +180,10 @@ void subghz_speaker_unmute(SubGhz* subghz); void subghz_txrx_stop(SubGhz* subghz); SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz); +SubGhzHopperState subghz_hopper_get_state(SubGhz* subghz); +void subghz_hopper_set_state(SubGhz* subghz, SubGhzHopperState state); +void subghz_hopper_remove_pause(SubGhz* subghz); +void subghz_subghz_hopper_set_pause(SubGhz* subghz); extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; From d8631d14890933e76f12df6e09756639294f46e7 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 17:19:02 +0300 Subject: [PATCH 140/216] SubGhz: remove direct reading subghz->lock --- .../main/subghz/scenes/subghz_scene_decode_raw.c | 5 +++-- .../main/subghz/scenes/subghz_scene_receiver.c | 6 +++--- .../subghz/scenes/subghz_scene_receiver_config.c | 2 +- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_i.c | 15 +++++++++++++++ applications/main/subghz/subghz_i.h | 4 ++++ applications/main/subghz/views/receiver.c | 14 +++++++------- applications/main/subghz/views/receiver.h | 2 +- 8 files changed, 35 insertions(+), 15 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index b9f2d236b..639db146f 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -159,7 +159,8 @@ void subghz_scene_decode_raw_on_enter(void* context) { FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_lock( + subghz->subghz_receiver, subghz_is_locked(subghz)); //TODO Doesn't matter in DecodeRAW subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz); @@ -242,7 +243,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverUnlock: - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); //TODO There is no such event in DecodeRAW consumed = true; break; default: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 8de7870a8..5b525a486 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -127,7 +127,7 @@ void subghz_scene_receiver_on_enter(void* context) { subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; } - subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); + subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz)); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeLive); //Load history to receiver @@ -262,7 +262,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverUnlock: - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); consumed = true; break; default: @@ -286,7 +286,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { notification_message(subghz->notifications, &sequence_blink_cyan_10); break; case SubGhzNotificationStateRxDone: - if(subghz->lock != SubGhzLockOn) { + if(!subghz_is_locked(subghz)) { notification_message(subghz->notifications, &subghz_sequence_rx); } else { notification_message(subghz->notifications, &subghz_sequence_rx_locked); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index ef8ffc9bd..7aa3d4e46 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -415,7 +415,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneSettingLock) { - subghz->lock = SubGhzLockOn; + subghz_lock(subghz); scene_manager_previous_scene(subghz->scene_manager); consumed = true; } diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 7e35346b8..f2bb87c8a 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -260,7 +260,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->threshold_rssi = subghz_threshold_rssi_alloc(); //init Worker & Protocol & History & KeyBoard - subghz->lock = SubGhzLockOff; + subghz_unlock(subghz); subghz->txrx = malloc(sizeof(SubGhzTxRx)); subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); subghz->txrx->preset->name = furi_string_alloc(); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 194b404db..e94f937bd 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -710,3 +710,18 @@ void subghz_speaker_unmute(SubGhz* subghz) { } } } + +void subghz_lock(SubGhz* subghz) { + furi_assert(subghz); + subghz->lock = SubGhzLockOn; +} + +void subghz_unlock(SubGhz* subghz) { + furi_assert(subghz); + subghz->lock = SubGhzLockOff; +} + +bool subghz_is_locked(SubGhz* subghz) { + furi_assert(subghz); + return (subghz->lock == SubGhzLockOn); +} \ No newline at end of file diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index f772c388c..7e3e9bab0 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -185,5 +185,9 @@ void subghz_hopper_set_state(SubGhz* subghz, SubGhzHopperState state); void subghz_hopper_remove_pause(SubGhz* subghz); void subghz_subghz_hopper_set_pause(SubGhz* subghz); +void subghz_lock(SubGhz* subghz); +void subghz_unlock(SubGhz* subghz); +bool subghz_is_locked(SubGhz* subghz); + extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 811a46698..6f272b6a6 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -49,7 +49,7 @@ typedef enum { } SubGhzViewReceiverBarShow; struct SubGhzViewReceiver { - SubGhzLock lock; + bool lock; uint8_t lock_count; FuriTimer* timer; View* view; @@ -95,10 +95,10 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { true); } -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; - if(lock == SubGhzLockOn) { + if(lock == true) { subghz_receiver->lock = lock; with_view_model( subghz_receiver->view, @@ -394,7 +394,7 @@ static void subghz_view_receiver_timer_callback(void* context) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); } else { - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); } subghz_receiver->lock_count = 0; @@ -404,7 +404,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; - if(subghz_receiver->lock == SubGhzLockOn) { + if(subghz_receiver->lock == true) { with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -424,7 +424,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, true); - //subghz_receiver->lock = SubGhzLockOff; + //subghz_receiver->lock = false; furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); } @@ -549,7 +549,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { // View allocation and configuration subghz_receiver->view = view_alloc(); - subghz_receiver->lock = SubGhzLockOff; + subghz_receiver->lock = false; subghz_receiver->lock_count = 0; view_allocate_model( subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel)); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index f5ec86b4b..54c1b3e7d 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -14,7 +14,7 @@ void subghz_view_receiver_set_mode( void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); -void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); +void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard); void subghz_view_receiver_set_callback( SubGhzViewReceiver* subghz_receiver, From 1387d8d5d652c81b9eeb8c5a193dc6b0dca75718 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 17:28:16 +0300 Subject: [PATCH 141/216] SubGhz: check load type file --- applications/main/subghz/helpers/subghz_types.h | 7 +++++++ applications/main/subghz/scenes/subghz_scene_saved.c | 2 +- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_i.c | 7 +++++++ applications/main/subghz/subghz_i.h | 3 +++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 3c5982427..700049237 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -80,6 +80,13 @@ typedef enum { SubGhzViewIdTestPacket, } SubGhzViewId; +/** SubGhz load type file */ +typedef enum { + SubGhzLoadTypeFileNoLoad, + SubGhzLoadTypeFileKey, + SubGhzLoadTypeFileRaw, +} SubGhzLoadTypeFile; + typedef enum { SubGhzViewReceiverModeLive, SubGhzViewReceiverModeFile, diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index 62ade3508..23d8ac39f 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -4,7 +4,7 @@ void subghz_scene_saved_on_enter(void* context) { SubGhz* subghz = context; if(subghz_load_protocol_from_file(subghz)) { - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index f2bb87c8a..6d565be5d 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -478,7 +478,7 @@ int32_t subghz_app(void* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { //Load Raw TX subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index e94f937bd..d8da55973 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -356,8 +356,10 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW + subghz->txrx->load_type_file = SubGhzLoadTypeFileRaw; subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); } else { + subghz->txrx->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), flipper_format_get_raw_stream(subghz->txrx->fff_data)); @@ -412,6 +414,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } } +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) { + furi_assert(subghz); + return subghz->txrx->load_type_file; +} + bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { furi_assert(subghz); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 7e3e9bab0..4be2b6e5f 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -86,6 +86,7 @@ struct SubGhzTxRx { bool ignore_magellan; SubGhzRxKeyState rx_key_state; + SubGhzLoadTypeFile load_type_file; bool debug_pin_state; }; @@ -189,5 +190,7 @@ void subghz_lock(SubGhz* subghz); void subghz_unlock(SubGhz* subghz); bool subghz_is_locked(SubGhz* subghz); +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); + extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; From 1567225a64b317f5b853e692d71b9d228293df39 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 17:47:49 +0300 Subject: [PATCH 142/216] SubGhz: remove direct reading subghz->txrx->rx_key_state --- .../subghz/scenes/subghz_scene_need_saving.c | 10 +++---- .../subghz/scenes/subghz_scene_read_raw.c | 30 +++++++++---------- .../subghz/scenes/subghz_scene_receiver.c | 14 ++++----- .../subghz/scenes/subghz_scene_save_success.c | 4 +-- .../main/subghz/scenes/subghz_scene_saved.c | 2 +- .../main/subghz/scenes/subghz_scene_start.c | 2 +- applications/main/subghz/subghz.c | 4 +-- applications/main/subghz/subghz_i.c | 10 +++++++ applications/main/subghz/subghz_i.h | 5 +++- 9 files changed, 47 insertions(+), 34 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index 5c6b9cc39..f6029e2c0 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -37,22 +37,22 @@ void subghz_scene_need_saving_on_enter(void* context) { bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneStay) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.event == SubGhzCustomEventSceneExit) { - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateExit) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_previous_scene(subghz->scene_manager); } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 33cd2ebb6..c2b0e5d35 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -71,7 +71,7 @@ void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; FuriString* file_name = furi_string_alloc(); - switch(subghz->txrx->rx_key_state) { + switch(subghz_rx_key_state_get(subghz)) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( subghz->subghz_read_raw, @@ -86,7 +86,7 @@ void subghz_scene_read_raw_on_enter(void* context) { SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); @@ -95,7 +95,7 @@ void subghz_scene_read_raw_on_enter(void* context) { SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); break; default: subghz_read_raw_set_status( @@ -103,7 +103,7 @@ void subghz_scene_read_raw_on_enter(void* context) { SubGhzReadRAWStatusStart, "", subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); break; } furi_string_free(file_name); @@ -133,9 +133,9 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? - if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || - (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || + (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { //Restore default setting @@ -175,13 +175,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWErase: - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { if(subghz_scene_read_raw_update_filename(subghz)) { furi_string_set(subghz->file_path_tmp, subghz->file_path); subghz_delete_file(subghz); } } - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); notification_message(subghz->notifications, &sequence_reset_rgb); consumed = true; break; @@ -191,7 +191,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); consumed = true; } else { @@ -214,7 +214,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz); if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, @@ -272,13 +272,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); consumed = true; break; case SubGhzCustomEventViewReadRAWREC: - if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { if(subghz_protocol_raw_save_to_file_init( @@ -294,7 +294,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_rx(subghz, subghz->txrx->preset->frequency); subghz->state_notifications = SubGhzNotificationStateRx; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { furi_string_set(subghz->error_str, "Function requires\nan SD card."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); @@ -307,7 +307,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } else { if(!scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 5b525a486..d52e37ff9 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -112,7 +112,7 @@ static void subghz_scene_add_to_history_callback( subghz_receiver_reset(receiver); furi_string_free(item_name); furi_string_free(item_time); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } void subghz_scene_receiver_on_enter(void* context) { @@ -121,10 +121,10 @@ void subghz_scene_receiver_on_enter(void* context) { FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); subghz_history_reset(subghz->txrx->history); - subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz)); @@ -142,7 +142,7 @@ void subghz_scene_receiver_on_enter(void* context) { furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->txrx->history, i)); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(item_name); furi_string_free(item_time); @@ -219,11 +219,11 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 85be80b2a..0a7fd8686 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -27,10 +27,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(!subghz->in_decoder_scene) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index 23d8ac39f..eca5ab801 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -5,7 +5,7 @@ void subghz_scene_saved_on_enter(void* context) { if(subghz_load_protocol_from_file(subghz)) { if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index 8777d2461..ba405c737 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -93,7 +93,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 6d565be5d..b64470860 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -273,7 +273,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->txrx_state = SubGhzTxRxStateSleep; subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz->txrx->debug_pin_state = false; if(!alloc_for_tx_only) { subghz->txrx->history = subghz_history_alloc(); @@ -480,7 +480,7 @@ int32_t subghz_app(void* p) { if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { //Load transmitter TX diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index d8da55973..b2275c4d3 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -731,4 +731,14 @@ void subghz_unlock(SubGhz* subghz) { bool subghz_is_locked(SubGhz* subghz) { furi_assert(subghz); return (subghz->lock == SubGhzLockOn); +} + +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) { + furi_assert(subghz); + subghz->rx_key_state = state; +} + +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { + furi_assert(subghz); + return subghz->rx_key_state; } \ No newline at end of file diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 4be2b6e5f..acbb1823a 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -85,7 +85,6 @@ struct SubGhzTxRx { bool ignore_auto_alarms; bool ignore_magellan; - SubGhzRxKeyState rx_key_state; SubGhzLoadTypeFile load_type_file; bool debug_pin_state; @@ -137,6 +136,7 @@ struct SubGhz { SubGhzFileEncoderWorker* decode_raw_file_worker_encoder; SubGhzThresholdRssi* threshold_rssi; + SubGhzRxKeyState rx_key_state; void* rpc_ctx; }; @@ -192,5 +192,8 @@ bool subghz_is_locked(SubGhz* subghz); SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); +void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); +SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); + extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; From e65a5e2b7cb8d34b15318f8aebeb528b856d01ba Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 6 May 2023 17:56:10 +0300 Subject: [PATCH 143/216] SubGhz: remove direct reading subghz->txrx->speaker_state --- .../main/subghz/scenes/subghz_scene_receiver_config.c | 5 +++-- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_i.c | 10 ++++++++++ applications/main/subghz/subghz_i.h | 5 ++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 7aa3d4e46..de78e002b 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -217,7 +217,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz->txrx->speaker_state = speaker_value[index]; + subghz_speaker_set_state(subghz, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -378,7 +378,8 @@ void subghz_scene_receiver_config_on_enter(void* context) { SPEAKER_COUNT, subghz_scene_receiver_config_set_speaker, subghz); - value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); + value_index = + value_index_uint32(subghz_speaker_get_state(subghz), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index b64470860..7e6cebe98 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -272,7 +272,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { } subghz->txrx->txrx_state = SubGhzTxRxStateSleep; subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; + subghz_speaker_set_state(subghz, SubGhzSpeakerStateDisable); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz->txrx->debug_pin_state = false; if(!alloc_for_tx_only) { diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index b2275c4d3..25d03915b 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -718,6 +718,16 @@ void subghz_speaker_unmute(SubGhz* subghz) { } } +void subghz_speaker_set_state(SubGhz* subghz, SubGhzSpeakerState state) { + furi_assert(subghz); + subghz->txrx->speaker_state = state; +} + +SubGhzSpeakerState subghz_speaker_get_state(SubGhz* subghz) { + furi_assert(subghz); + return subghz->txrx->speaker_state; +} + void subghz_lock(SubGhz* subghz) { furi_assert(subghz); subghz->lock = SubGhzLockOn; diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index acbb1823a..63687e97c 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -124,9 +124,10 @@ struct SubGhz { SubGhzTestStatic* subghz_test_static; SubGhzTestPacket* subghz_test_packet; #endif - FuriString* error_str; SubGhzSetting* setting; SubGhzLastSettings* last_settings; + + FuriString* error_str; SubGhzLock lock; bool in_decoder_scene; @@ -178,6 +179,8 @@ void subghz_speaker_on(SubGhz* subghz); void subghz_speaker_off(SubGhz* subghz); void subghz_speaker_mute(SubGhz* subghz); void subghz_speaker_unmute(SubGhz* subghz); +void subghz_speaker_set_state(SubGhz* subghz, SubGhzSpeakerState state); +SubGhzSpeakerState subghz_speaker_get_state(SubGhz* subghz); void subghz_txrx_stop(SubGhz* subghz); SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz); From 1db6d4dbe82f7fc40a68e4e8dad5f0341d6e8ad8 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sat, 6 May 2023 18:34:39 +0100 Subject: [PATCH 144/216] Bump v46 --- fbt_options.py | 2 +- scripts/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fbt_options.py b/fbt_options.py index 3fdcc6e30..27503cbd6 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -14,7 +14,7 @@ DEBUG = 0 # Suffix to add to files when building distribution # If OS environment has DIST_SUFFIX set, it will be used instead -DIST_SUFFIX = "XFW-0045_04052023" +DIST_SUFFIX = "XFW-0046_06052023" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" diff --git a/scripts/version.py b/scripts/version.py index 9e543ac9c..7d3643765 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,5 +1,5 @@ #!/usb/bin/env python3 -VERSION = "XFW-0045" +VERSION = "XFW-0046" import json import os From 954780ed24c63adfdda153d88eddd4abb3a28c53 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Sun, 7 May 2023 14:40:38 -0400 Subject: [PATCH 145/216] Fix storage.py exist_dir logic (#2639) * Fix storage.py exist_dir logic. This method would return true if the given path existed as either a directory or a file, which is what the plain exist method is for. --- scripts/flipper/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index 9f6f52156..4640262bc 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -323,7 +323,7 @@ class FlipperStorage: return False raise FlipperStorageException.from_error_code(path, error_code) - return True + return response == b"Directory" or response.startswith(b"Storage") def exist_file(self, path: str): """Does file exist on Flipper""" From 85928b6e8abb4e280ae26df2476a9c48c72337d9 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 7 May 2023 21:29:35 +0100 Subject: [PATCH 146/216] Upd+fix cli app (thanks @xMasterX) bydlo kod FTW! --- .../external/cli_bridge/cli_control.c | 7 +--- .../external/cli_bridge/cligui_main.c | 15 +++++++- .../external/cli_bridge/internal_defs.h | 38 ++++++++++++------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/applications/external/cli_bridge/cli_control.c b/applications/external/cli_bridge/cli_control.c index e159d7424..80a0fd490 100644 --- a/applications/external/cli_bridge/cli_control.c +++ b/applications/external/cli_bridge/cli_control.c @@ -72,12 +72,7 @@ void latch_tx_handler() { session.is_connected = &session_connected; cli_session_close(global_cli); cli_session_open(global_cli, &session); - // Unlock loader-lock - Loader* loader = furi_record_open(RECORD_LOADER); - Loader_internal* loader_i = (Loader_internal*)loader; - loader_i->lock_count = 0; furi_record_close(RECORD_CLI); - furi_record_close(RECORD_LOADER); } void unlatch_tx_handler(bool persist) { Cli* global_cli = furi_record_open(RECORD_CLI); @@ -106,4 +101,4 @@ void unlatch_tx_handler(bool persist) { // At this point, all cli_vcp functions should be back. furi_stream_buffer_free(rx_stream); furi_stream_buffer_free(tx_stream); -} \ No newline at end of file +} diff --git a/applications/external/cli_bridge/cligui_main.c b/applications/external/cli_bridge/cligui_main.c index 6b6ec2797..ef53203f0 100644 --- a/applications/external/cli_bridge/cligui_main.c +++ b/applications/external/cli_bridge/cligui_main.c @@ -65,7 +65,13 @@ static void input_callback_wrapper(InputEvent* event, void* context) { int32_t cligui_main(void* p) { UNUSED(p); - loader_unlock(furi_record_open(RECORD_LOADER)); + + // Unlock loader-lock and save app thread + FuriThread* temp_save_appthr; + Loader* loader = furi_record_open(RECORD_LOADER); + Loader_internal* loader_i = (Loader_internal*)loader; + temp_save_appthr = loader_i->app.thread; + loader_unlock(loader); furi_record_close(RECORD_LOADER); CliguiApp* cligui = malloc(sizeof(CliguiApp)); @@ -132,5 +138,12 @@ int32_t cligui_main(void* p) { free(cligui->data); free(cligui); + // Don't touch system loader!!! We restoring previous app thread here, we love kostily and velosipedy, bydlo kod forever! + + Loader* loader1 = furi_record_open(RECORD_LOADER); + Loader_internal* loader_ii = (Loader_internal*)loader1; + loader_ii->app.thread = temp_save_appthr; + furi_record_close(RECORD_LOADER); + return 0; } diff --git a/applications/external/cli_bridge/internal_defs.h b/applications/external/cli_bridge/internal_defs.h index 09fe6169c..9758b9aae 100644 --- a/applications/external/cli_bridge/internal_defs.h +++ b/applications/external/cli_bridge/internal_defs.h @@ -5,6 +5,10 @@ #include #include #include +#include +#include +#include +#include typedef struct { FuriThreadStdoutWriteCallback write_callback; @@ -68,24 +72,32 @@ typedef struct { } ViewPort_internal; typedef struct { - FuriThreadId loader_thread; + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; - const void* application; - FuriThread* application_thread; - char* application_arguments; + void (*closed_callback)(void*); + void* closed_callback_context; - void* cli; - void* gui; + void (*click_callback)(const char*, void*); + void* click_callback_context; - void* view_dispatcher; - void* primary_menu; - // void* plugins_menu; - // void* debug_menu; - void* settings_menu; + FuriThread* thread; +} LoaderMenu_internal; - volatile uint8_t lock_count; +typedef struct { + char* args; + char* name; + FuriThread* thread; + bool insomniac; +} LoaderAppData_internal; - void* pubsub; +typedef struct { + FuriPubSub* pubsub; + FuriMessageQueue* queue; + LoaderMenu_internal* loader_menu; + LoaderAppData_internal app; } Loader_internal; typedef struct { From f7dd77795a700ec737505709573fc3f2bdc3a9ca Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 8 May 2023 14:01:52 +0300 Subject: [PATCH 147/216] ufbt: deploying sample ufbt automation for new apps; added `source "ufbt -s env"` for toolchain access (#2648) --- SConstruct | 6 +++ documentation/fbt.md | 1 + scripts/fbt_tools/fbt_apps.py | 4 +- scripts/fbt_tools/fbt_help.py | 3 ++ scripts/ufbt/SConstruct | 11 ++++- .../app_template/.github/workflows/build.yml | 41 +++++++++++++++++++ scripts/ufbt/site_tools/ufbt_help.py | 3 ++ 7 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 scripts/ufbt/project_template/app_template/.github/workflows/build.yml diff --git a/SConstruct b/SConstruct index 090a92599..12f1166eb 100644 --- a/SConstruct +++ b/SConstruct @@ -335,3 +335,9 @@ vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*")) distenv.Precious(vscode_dist) distenv.NoClean(vscode_dist) distenv.Alias("vscode_dist", vscode_dist) + +# Configure shell with build tools +distenv.PhonyTarget( + "env", + "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", +) diff --git a/documentation/fbt.md b/documentation/fbt.md index 23b2e2b55..d9eb8f4aa 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -13,6 +13,7 @@ To use `fbt`, you only need `git` installed in your system. > However, if you wish to use tools supplied with the toolchain outside `fbt`, you can open an *fbt shell*, with properly configured environment. > - On Windows, simply run `scripts/toolchain/fbtenv.cmd`. > - On Linux & MacOS, run `source scripts/toolchain/fbtenv.sh` in a new shell. + > - You can also type ```. `./fbt -s env` ``` in your shell. (Keep the "." at the beginning.) If your system is not supported by pre-built toolchain variants or you want to use custom versions of dependencies, you can `set FBT_NOENV=1`. `fbt` will skip toolchain & environment configuration and will expect all tools to be available on your system's `PATH`. *(this option is not available on Windows)* diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 053a69503..cbb3bf726 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -9,6 +9,7 @@ from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import StopError from SCons.Warnings import WarningOnByDefault, warn +from SCons.Script import GetOption # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps @@ -28,7 +29,8 @@ def LoadAppManifest(env, entry): env["APPMGR"].load_manifest(app_manifest_file_path, entry) env.Append(PY_LINT_SOURCES=[app_manifest_file_path]) except FlipperManifestException as e: - warn(WarningOnByDefault, str(e)) + if not GetOption("silent"): + warn(WarningOnByDefault, str(e)) def PrepareApplicationsBuild(env): diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index afdb36665..c7452af98 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -34,6 +34,9 @@ Other: firmware_pvs: generate a PVS-Studio report +How to open a shell with toolchain environment and other build tools: + In your shell, type "source `./fbt -s env`". You can also use "." instead of "source". + For more targets & info, see documentation/fbt.md """ diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index fdb51981b..3f623ebc8 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -380,8 +380,9 @@ dist_env.Alias("vscode_dist", vscode_dist) # Creating app from base template dist_env.SetDefault(FBT_APPID=appenv.subst("$APPID") or "template") +app_template_dir = project_template_dir.Dir("app_template") app_template_dist = [] -for template_file in project_template_dir.Dir("app_template").glob("*"): +for template_file in app_template_dir.glob("*"): dist_file_name = dist_env.subst(template_file.name) if template_file.name.endswith(".png"): app_template_dist.append( @@ -397,12 +398,13 @@ for template_file in project_template_dir.Dir("app_template").glob("*"): }, ) ) - AddPostAction( app_template_dist[-1], [ Mkdir(original_app_dir.Dir("images")), Touch(original_app_dir.Dir("images").File(".gitkeep")), + # scons' glob ignores .dot directories, so we need to copy .github manually + Copy(original_app_dir.Dir(".github"), app_template_dir.Dir(".github")), ], ) dist_env.Precious(app_template_dist) @@ -440,3 +442,8 @@ else: raise UserError(f"Dolphin folder not found: {dolphin_src_dir}") dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None)) + +dist_env.PhonyTarget( + "env", + "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", +) diff --git a/scripts/ufbt/project_template/app_template/.github/workflows/build.yml b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml new file mode 100644 index 000000000..0834f8379 --- /dev/null +++ b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: "FAP: Build for multiple SDK sources" +# This will build your app for dev and release channels on GitHub. +# It will also build your app every day to make sure it's up to date with the latest SDK changes. +# See https://github.com/marketplace/actions/build-flipper-application-package-fap for more information + +on: + push: + ## put your main branch name under "braches" + #branches: + # - master + pull_request: + schedule: + # do a build every day + - cron: "1 1 * * *" + +jobs: + ufbt-build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - name: dev channel + sdk-channel: dev + - name: release channel + sdk-channel: release + # You can add unofficial channels here. See ufbt action docs for more info. + name: 'ufbt: Build for ${{ matrix.name }}' + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Build with ufbt + uses: flipperdevices/flipperzero-ufbt-action@v0.1.1 + id: build-app + with: + sdk-channel: ${{ matrix.sdk-channel }} + - name: Upload app artifacts + uses: actions/upload-artifact@v3 + with: + # See ufbt action docs for other output variables + name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }} + path: ${{ steps.build-app.outputs.fap-artifacts }} diff --git a/scripts/ufbt/site_tools/ufbt_help.py b/scripts/ufbt/site_tools/ufbt_help.py index da6ff6e51..3f13edcdb 100644 --- a/scripts/ufbt/site_tools/ufbt_help.py +++ b/scripts/ufbt/site_tools/ufbt_help.py @@ -40,6 +40,9 @@ How to create a new application: 2. Run `ufbt vscode_dist create APPID=myapp` 3. In VSCode, open the folder and start editing. 4. Run `ufbt launch` to build and upload your application. + +How to open a shell with toolchain environment and other build tools: + In your shell, type "source `ufbt -s env`". You can also use "." instead of "source". """ From 538f96f0ac43576383620b0faa0686ca35207b49 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 8 May 2023 14:11:23 +0300 Subject: [PATCH 148/216] [FL-3300] API version in UI (#2649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * desktop, about: replaced commit# with API version * scripts: storage: added approx speed for file uploads * scripts: selfupdate: use folder name by default * vscode: fixed broken get_blackmagic shell integration on *nix Co-authored-by: あく --- .vscode/example/launch.json | 7 +++-- .vscode/extensions.json | 5 ++-- .../desktop/views/desktop_view_debug.c | 7 +++-- applications/settings/about/about.c | 8 ++++-- scripts/flipper/storage.py | 26 +++++++++++-------- scripts/selfupdate.py | 2 +- .../project_template/.vscode/extensions.json | 3 ++- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index f7a9f8269..4cab026fa 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -11,11 +11,10 @@ "args": { "useSingleResult": true, "env": { - "PATH": "${workspaceFolder};${env:PATH}", - "FBT_QUIET": 1 + "PATH": "${workspaceFolder}${command:extension.commandvariable.envListSep}${env:PATH}" }, - "command": "fbt get_blackmagic", - "description": "Get Blackmagic device", + "command": "fbt -s get_blackmagic", + "description": "Get Blackmagic device" } } ], diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b5791a91e..ead935b08 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -8,11 +8,12 @@ "amiralizadeh9480.cpp-helper", "marus25.cortex-debug", "zxh404.vscode-proto3", - "augustocdias.tasks-shell-input" + "augustocdias.tasks-shell-input", + "rioj7.command-variable" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [ "twxs.cmake", "ms-vscode.cmake-tools" ] -} +} \ No newline at end of file diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index e679cf636..7a16c0847 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -65,13 +65,16 @@ void desktop_debug_render(Canvas* canvas, void* model) { version_get_builddate(ver)); canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer); + uint16_t api_major, api_minor; + furi_hal_info_get_api_version(&api_major, &api_minor); snprintf( buffer, sizeof(buffer), - "%s%s [%s] %s", + "%s%s [%d.%d] %s", version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), - version_get_gitbranchnum(ver), + api_major, + api_minor, c2_ver ? c2_ver->StackTypeString : ""); canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 61c724966..688103306 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -7,6 +7,7 @@ #include #include #include +#include typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); @@ -134,14 +135,17 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* if(!ver) { //-V1051 furi_string_cat_printf(buffer, "No info\n"); } else { + uint16_t api_major, api_minor; + furi_hal_info_get_api_version(&api_major, &api_minor); furi_string_cat_printf( buffer, - "%s [%s]\n%s%s [%s] %s\n[%d] %s", + "%s [%s]\n%s%s [%d.%d] %s\n[%d] %s", version_get_version(ver), version_get_builddate(ver), version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), - version_get_gitbranchnum(ver), + api_major, + api_minor, c2_ver ? c2_ver->StackTypeString : "", version_get_target(ver), version_get_gitbranch(ver)); diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index 4640262bc..f4d622bfe 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -1,12 +1,13 @@ -import os -import sys -import serial -import time -import hashlib -import math -import logging -import posixpath import enum +import hashlib +import logging +import math +import os +import posixpath +import sys +import time + +import serial def timing(func): @@ -236,6 +237,7 @@ class FlipperStorage: filesize = os.fstat(file.fileno()).st_size buffer_size = self.chunk_size + start_time = time.time() while True: filedata = file.read(buffer_size) size = len(filedata) @@ -254,11 +256,13 @@ class FlipperStorage: self.port.write(filedata) self.read.until(self.CLI_PROMPT) - percent = str(math.ceil(file.tell() / filesize * 100)) + ftell = file.tell() + percent = str(math.ceil(ftell / filesize * 100)) total_chunks = str(math.ceil(filesize / buffer_size)) - current_chunk = str(math.ceil(file.tell() / buffer_size)) + current_chunk = str(math.ceil(ftell / buffer_size)) + approx_speed = ftell / (time.time() - start_time + 0.0001) sys.stdout.write( - f"\r{percent}%, chunk {current_chunk} of {total_chunks}" + f"\r{percent}%, chunk {current_chunk} of {total_chunks} @ {approx_speed/1024:.2f} kb/s" ) sys.stdout.flush() print() diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py index 1ce0b8376..d222bf249 100644 --- a/scripts/selfupdate.py +++ b/scripts/selfupdate.py @@ -15,7 +15,7 @@ class Main(App): self.parser.add_argument("manifest_path", help="Manifest path") self.parser.add_argument( - "--pkg_dir_name", help="Update dir name", default="pcbundle", required=False + "--pkg_dir_name", help="Update dir name", default=None, required=False ) self.parser.set_defaults(func=self.install) diff --git a/scripts/ufbt/project_template/.vscode/extensions.json b/scripts/ufbt/project_template/.vscode/extensions.json index 35f90700a..ead935b08 100644 --- a/scripts/ufbt/project_template/.vscode/extensions.json +++ b/scripts/ufbt/project_template/.vscode/extensions.json @@ -8,7 +8,8 @@ "amiralizadeh9480.cpp-helper", "marus25.cortex-debug", "zxh404.vscode-proto3", - "augustocdias.tasks-shell-input" + "augustocdias.tasks-shell-input", + "rioj7.command-variable" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [ From 6fefa82817f708b2dfce44f4dd9449298aac6429 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 8 May 2023 14:26:22 +0100 Subject: [PATCH 149/216] Move U2F counter back to sd, only key on internal --- applications/main/u2f/u2f_app.c | 2 +- applications/main/u2f/u2f_data.h | 4 +- .../services/storage/storages/storage_int.c | 37 +++++-------------- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/applications/main/u2f/u2f_app.c b/applications/main/u2f/u2f_app.c index 60500152a..fb9b4241c 100644 --- a/applications/main/u2f/u2f_app.c +++ b/applications/main/u2f/u2f_app.c @@ -29,7 +29,7 @@ U2fApp* u2f_app_alloc() { app->notifications = furi_record_open(RECORD_NOTIFICATION); Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, U2F_CNT_OLD_FILE, U2F_CNT_FILE); + storage_common_rename(storage, U2F_CNT_OLD_FILE, U2F_CNT_FILE); storage_common_copy(storage, U2F_KEY_OLD_FILE, U2F_KEY_FILE); furi_record_close(RECORD_STORAGE); diff --git a/applications/main/u2f/u2f_data.h b/applications/main/u2f/u2f_data.h index f3c62f89d..5c887ba1d 100644 --- a/applications/main/u2f/u2f_data.h +++ b/applications/main/u2f/u2f_data.h @@ -9,10 +9,10 @@ extern "C" { #define U2F_DATA_FOLDER EXT_PATH("u2f/") #define U2F_CERT_FILE U2F_DATA_FOLDER "assets/cert.der" #define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "assets/cert_key.u2f" +#define U2F_CNT_OLD_FILE INT_PATH(".cnt.u2f") #define U2F_KEY_OLD_FILE U2F_DATA_FOLDER "key.u2f" -#define U2F_CNT_OLD_FILE U2F_DATA_FOLDER "cnt.u2f" +#define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f" #define U2F_KEY_FILE INT_PATH(".key.u2f") -#define U2F_CNT_FILE INT_PATH(".cnt.u2f") bool u2f_data_check(bool cert_only); diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index 5342c2bdd..8a2fef53b 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -195,30 +195,19 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { if(need_format) { // Backup U2F keys // lfs_file_t file; - // uint8_t* cnt = NULL; - // uint32_t cnt_size; // uint8_t* key = NULL; // uint32_t key_size; // if(lfs_mount(lfs, &lfs_data->config) == 0) { // FURI_LOG_I(TAG, "Factory reset: Mounted for backup"); - // if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_RDONLY) == 0) { - // cnt_size = file.ctz.size; - // cnt = malloc(cnt_size); - // if(lfs_file_read(lfs, &file, cnt, cnt_size) != (int32_t)cnt_size) { - // free(cnt); - // cnt = NULL; + // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_RDONLY) == 0) { + // key_size = file.ctz.size; + // key = malloc(key_size); + // if(lfs_file_read(lfs, &file, key, key_size) != (int32_t)key_size) { + // free(key); + // key = NULL; // } // lfs_file_close(lfs, &file); - // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_RDONLY) == 0) { - // key_size = file.ctz.size; - // key = malloc(key_size); - // if(lfs_file_read(lfs, &file, key, key_size) != (int32_t)key_size) { - // free(key); - // key = NULL; - // } - // lfs_file_close(lfs, &file); - // } // } // if(lfs_unmount(lfs) == 0) { @@ -239,19 +228,12 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { storage->status = StorageStatusOK; // Restore U2F keys - // if(cnt != NULL && key != NULL) { - // if(lfs_file_open(lfs, &file, ".cnt.u2f", LFS_O_WRONLY | LFS_O_CREAT) == 0) { - // lfs_file_write(lfs, &file, cnt, cnt_size); + // if(key != NULL) { + // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_WRONLY | LFS_O_CREAT) == 0) { + // lfs_file_write(lfs, &file, key, key_size); // lfs_file_close(lfs, &file); - // if(lfs_file_open(lfs, &file, ".key.u2f", LFS_O_WRONLY | LFS_O_CREAT) == - // 0) { - // lfs_file_write(lfs, &file, key, key_size); - // lfs_file_close(lfs, &file); - // } // } // } - // if(cnt != NULL) free(cnt); - // if(key != NULL) free(key); } else { FURI_LOG_E(TAG, "Factory reset: Mount after format failed"); storage->status = StorageStatusNotMounted; @@ -260,6 +242,7 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { FURI_LOG_E(TAG, "Factory reset: Format failed"); storage->status = StorageStatusNoFS; } + // if(key != NULL) free(key); } else { // Normal err = lfs_mount(lfs, &lfs_data->config); From 02a658e0c73bddab0c27858b0acfcae53e785c0d Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 8 May 2023 14:28:29 +0100 Subject: [PATCH 150/216] Clear internal too on pin reset combo (U2F key) --- firmware/targets/f7/src/recovery.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/targets/f7/src/recovery.c b/firmware/targets/f7/src/recovery.c index f1bfe5383..700fb03c6 100644 --- a/firmware/targets/f7/src/recovery.c +++ b/firmware/targets/f7/src/recovery.c @@ -57,6 +57,7 @@ void flipper_boot_recovery_exec() { if(!counter) { furi_hal_rtc_set_flag(FuriHalRtcFlagResetPin); + furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_set_pin_fails(0); furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); } From ee85541d2a1ffcf5f3d6dffdb4b6e54aa178584d Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 8 May 2023 21:55:51 +0300 Subject: [PATCH 151/216] SubGhz: refactoring subghz_scene_set_type.csubghz_scene_set_type.c --- .../main/subghz/helpers/subghz_custom_event.h | 6 +- .../subghz/scenes/subghz_scene_set_seed.c | 83 +-- .../subghz/scenes/subghz_scene_set_type.c | 635 ++++++------------ applications/main/subghz/subghz_i.c | 341 ++++++++++ applications/main/subghz/subghz_i.h | 82 +++ 5 files changed, 643 insertions(+), 504 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index ad49bf09b..cd163a653 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -36,12 +36,12 @@ typedef enum { SubmenuIndexCAME24bit868, SubmenuIndexCAMETwee, SubmenuIndexCAMESpace, - SubmenuIndexPricenton, + SubmenuIndexPricenton433, SubmenuIndexPricenton315, SubmenuIndexBETT_433, SubmenuIndexLinear_300_00, - SubmenuIndexNeroSketch, - SubmenuIndexNeroRadio, + SubmenuIndexNeroSketch, //Deleted in OFW + SubmenuIndexNeroRadio, //Deleted in OFW SubmenuIndexGateTX, SubmenuIndexDoorHan_315_00, SubmenuIndexDoorHan_433_92, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index aa2a270f3..336331126 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -1,6 +1,4 @@ #include "../subghz_i.h" -#include -#include #define TAG "SubGhzSetSeed" @@ -50,34 +48,15 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { subghz->txrx->secure_data->seed[2] << 8 | subghz->txrx->secure_data->seed[3]; - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); - if(subghz->txrx->transmitter) { - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - subghz_protocol_keeloq_bft_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - fix_part & 0x0FFFFFFF, - fix_part >> 28, - cnt, - seed, - "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] = (seed >> 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; - } - - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( + subghz, + "AM650", + 433920000, + fix_part & 0x0FFFFFFF, + fix_part >> 28, + cnt, + seed, + "BFT"); if(!generated_protocol) { furi_string_set( @@ -101,40 +80,28 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { subghz->txrx->secure_data->seed[2] << 8 | subghz->txrx->secure_data->seed[3]; - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH"); - if(subghz->txrx->transmitter) { - SubGhzCustomEvent state = - scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); - - if(state == SubmenuIndexFaacSLH_433) { - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - } else if(state == SubmenuIndexFaacSLH_868) { - subghz_preset_init(subghz, "AM650", 868350000, NULL, 0); - } - subghz_protocol_faac_slh_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, + if(state == SubmenuIndexFaacSLH_433) { + generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( + subghz, + "AM650", + 433920000, fix_part >> 4, fix_part & 0xf, (cnt & 0xFFFFF), seed, - "FAAC_SLH", - subghz->txrx->preset); - // RogueMaster dont steal! - 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] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex( - subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - - generated_protocol = true; + "FAAC_SLH"); + } else if(state == SubmenuIndexFaacSLH_868) { + generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( + subghz, + "AM650", + 868350000, + fix_part >> 4, + fix_part & 0xf, + (cnt & 0xFFFFF), + seed, + "FAAC_SLH"); } - subghz_transmitter_free(subghz->txrx->transmitter); - if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index e871a6439..2ce806067 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,102 +1,9 @@ #include "../subghz_i.h" -#include -#include -#include -#include -#include #include -#include -#include #include #define TAG "SubGhzSetType" -bool subghz_scene_set_type_submenu_gen_data_protocol( - void* context, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t frequency, - const char* preset_name) { - furi_assert(context); - SubGhz* subghz = context; - - bool res = false; - - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); - - if(subghz->txrx->decoder_result == NULL) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_keeloq( - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - manufacture_name, - subghz->txrx->preset)) { - flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", manufacture_name); - res = true; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - if(!res) { - furi_string_set(subghz->error_str, "Function requires\nan SD card with\nfresh databases."); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); - } - return res; -} - void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -306,7 +213,7 @@ void subghz_scene_set_type_on_enter(void* context) { submenu_add_item( subghz->submenu, "Princeton 433MHz", - SubmenuIndexPricenton, + SubmenuIndexPricenton433, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -385,7 +292,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { - //ToDo Fix uint32_t key = subghz_random_serial(); switch(event.event) { case SubmenuIndexFaacSLH_868: @@ -397,258 +303,239 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexBFTClone: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); break; - case SubmenuIndexPricenton: + case SubmenuIndexPricenton433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) { - uint32_t te = 400; - flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol_and_te( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexPricenton315: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 315000000, "AM650")) { - uint32_t te = 400; - flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol_and_te( + subghz, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexCAME12bit868: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 868350000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit868: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 868350000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexBETT_433: key = (key & 0x0000FFF0); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_BETT_NAME, key, 18, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_BETT_NAME, key, 18); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; - // case SubmenuIndexNeroSketch: - // /* code */ - // break; - // case SubmenuIndexNeroRadio: - // /* code */ - // break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_data_protocol( + subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexBeninca433: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 433920000, - (key & 0x000FFF00) | 0x00800080, - 0x1, - 0x0005, - "Beninca")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 433920000, + (key & 0x000FFF00) | 0x00800080, + 0x1, + 0x0005, + "Beninca"); + 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 SubmenuIndexBeninca868: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 868350000, - (key & 0x000FFF00) | 0x00800080, - 0x1, - 0x0005, - "Beninca")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 868350000, + (key & 0x000FFF00) | 0x00800080, + 0x1, + 0x0005, + "Beninca"); + 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 SubmenuIndexAllmatic433: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 433920000, - (key & 0x00FFFF00) | 0x01000011, - 0xC, - 0x0005, - "Beninca")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 433920000, + (key & 0x00FFFF00) | 0x01000011, + 0xC, + 0x0005, + "Beninca"); + 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 SubmenuIndexAllmatic868: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 868350000, - (key & 0x00FFFF00) | 0x01000011, - 0xC, - 0x0005, - "Beninca")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 868350000, + (key & 0x00FFFF00) | 0x01000011, + 0xC, + 0x0005, + "Beninca"); + 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 SubmenuIndexElmesElectronic: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 433920000, - (key & 0x00FFFFFF) | 0x02000000, - 0x2, - 0x0003, - "Elmes_Poland")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 433920000, + (key & 0x00FFFFFF) | 0x02000000, + 0x2, + 0x0003, + "Elmes_Poland"); + 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 SubmenuIndexANMotorsAT4: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 433920000, - (key & 0x000FFFFF) | 0x04700000, - 0x2, - 0x0021, - "AN-Motors")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 433920000, + (key & 0x000FFFFF) | 0x04700000, + 0x2, + 0x0021, + "AN-Motors"); + 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 SubmenuIndexAprimatic: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, - "AM650", - 433920000, - (key & 0x000FFFFF) | 0x00600000, - 0x4, - 0x0003, - "Aprimatic")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, + "AM650", + 433920000, + (key & 0x000FFFFF) | 0x00600000, + 0x4, + 0x0003, + "Aprimatic"); + 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 SubmenuIndexGibidi433: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi"); + 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 SubmenuIndexGSN: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN"); + 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 SubmenuIndexIronLogic: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic"); + 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 SubmenuIndexSommer_FM_434: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); + 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 SubmenuIndexSommer_FM_868: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); + 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 SubmenuIndexDTMNeo433: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo"); + 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 SubmenuIndexCAMESpace: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space"); + 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 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); + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( + subghz, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0002, key & 0x000FFFFF, "BFT"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -656,22 +543,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAlutechAT4N: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_alutech_at_4n_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - (key & 0x000FFFFF) | 0x00100000, - 0x44, - 0x0003, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_scene_set_type_submenu_gen_data_alutech_at_4n( + subghz, "AM650", 433920000, (key & 0x000FFFFF) | 0x00100000, 0x44, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -679,58 +552,35 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSomfyTelis: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); - subghz_preset_init(subghz, "AM650", 433920000, 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) { + generated_protocol = subghz_scene_set_type_submenu_gen_data_somfy_telis( + subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003); + if(!generated_protocol) { //TODO does not use databases 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: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); + 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_315_00: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); + 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 SubmenuIndexNiceFlorS_433_92: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); - subghz_preset_init(subghz, "AM650", 433920000, 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, - false); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( + subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, false); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -738,23 +588,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } 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", 433920000, 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; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( + subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, true); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -762,124 +597,38 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexNiceSmilo_433_92: - if(subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo")) { - generated_protocol = true; + generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo"); + 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 SubmenuIndexLiftMaster_315_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 315000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 390000000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 390000000); break; case SubmenuIndexLiftMaster_433_00: - while(!subghz_protocol_secplus_v1_check_fixed(key)) { - key = subghz_random_serial(); - } - if(subghz_scene_set_type_submenu_gen_data_protocol( - subghz, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)key << 32 | 0xE6000000, - 42, - 433920000, - "AM650")) { - generated_protocol = true; - } + generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 433920000); break; case SubmenuIndexSecPlus_v2_310_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 310000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = + subghz_gen_secplus_v2_protocol(subghz, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 315000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = + subghz_gen_secplus_v2_protocol(subghz, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 390000000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = + subghz_gen_secplus_v2_protocol(subghz, "AM650", 390000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_433_00: - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - key, - 0x68, - 0xE500000, - subghz->txrx->preset); - generated_protocol = true; - } else { - generated_protocol = false; - } - subghz_transmitter_free(subghz->txrx->transmitter); + generated_protocol = + subghz_gen_secplus_v2_protocol(subghz, "AM650", 433920000, key, 0x68, 0xE500000); break; default: return false; diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 25d03915b..0226921ad 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -751,4 +751,345 @@ void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) { SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { furi_assert(subghz); return subghz->rx_key_state; +} + +//#############Create new Key############## +#include +#include +#include +#include +#include + +bool subghz_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhz* subghz = context; + + bool res = false; + + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + subghz->txrx->decoder_result = + subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); + + if(subghz->txrx->decoder_result == NULL) { + furi_string_set(subghz->error_str, "Protocol not\nfound!"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_gen_data_protocol_and_te( + SubGhz* subghz, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(subghz); + bool ret = false; + if(subghz_gen_data_protocol(subghz, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + + if(subghz->txrx->transmitter && + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + manufacture_name, + subghz->txrx->preset)) { + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", manufacture_name); + res = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + + if(subghz->txrx->transmitter && + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + subghz->txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> 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"); + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); + subghz_preset_init(subghz, preset_name, frequency, 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, + serial, + btn, + cnt, + subghz->txrx->preset, + nice_one)) { + res = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + + if(subghz->txrx->transmitter && + subghz_protocol_faac_slh_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + subghz->txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + + if(subghz->txrx->transmitter && + subghz_protocol_alutech_at_4n_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + subghz->txrx->preset)) { + res = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhz* subghz = context; + + bool res = false; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); + subghz_preset_init(subghz, preset_name, frequency, NULL, 0); + + if(subghz->txrx->transmitter && + subghz_protocol_somfy_telis_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + subghz->txrx->preset)) { + res = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + return res; +} + +bool subghz_gen_secplus_v2_protocol( + SubGhz* subghz, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(subghz); + + bool ret = false; + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_preset_init(subghz, name_preset, frequency, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + serial, + btn, + cnt, + subghz->txrx->preset); + ret = true; + } + return ret; +} + +bool subghz_gen_secplus_v1_protocol(SubGhz* subghz, const char* name_preset, uint32_t frequency) { + furi_assert(subghz); + + bool ret = false; + uint32_t serial = subghz_random_serial(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = subghz_random_serial(); + } + if(subghz_gen_data_protocol( + subghz, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; } \ No newline at end of file diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 63687e97c..73b5221cb 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -198,5 +198,87 @@ SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); +//#############Create new Key############## +bool subghz_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +bool subghz_gen_data_protocol_and_te( + SubGhz* subghz, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +bool subghz_scene_set_type_submenu_gen_data_keeloq( + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one); + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_gen_secplus_v2_protocol( + SubGhz* subghz, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +bool subghz_gen_secplus_v1_protocol(SubGhz* subghz, const char* name_preset, uint32_t frequency); + extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; From 268b88be0d8fbdaca359c3e49411f4f5c699f64b Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 9 May 2023 00:30:33 +0300 Subject: [PATCH 152/216] [FL-3285] Removed STM32CubeWB module (#2608) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * libs: removed STM32CubeWB module; split cube into 3 submodules * fixed f18 version * fbt: options: fixed expected stack version * pvs: updated for new paths * fbt: ep: multithreaded submodule update * libs: stm32cubewb: fixed duplicate include path; renamed to stm32wb; codeowners: updated paths; docs: updated paths * pvs: updated paths * libs: added cmsis_core from ARM sources, v.5.4.0, from https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/Core/Include * Updated stm32wb_copro structure * PVS: exclude cmsis core from analysis --------- Co-authored-by: あく --- .github/CODEOWNERS | 2 +- .gitmodules | 12 +- .pvsoptions | 2 +- documentation/Doxyfile | 4 +- documentation/OTA.md | 2 +- fbt | 3 +- fbt.cmd | 2 +- fbt_options.py | 11 +- firmware/SConscript | 2 +- firmware/targets/f18/api_symbols.csv | 58 +- firmware/targets/f18/target.json | 4 +- firmware/targets/f7/api_symbols.csv | 58 +- firmware/targets/f7/furi_hal/furi_hal_flash.c | 2 +- firmware/targets/f7/target.json | 4 +- lib/ReadMe.md | 4 +- lib/SConscript | 2 +- lib/STM32CubeWB | 1 - lib/STM32CubeWB.scons | 72 - lib/cmsis_core/cmsis_armcc.h | 894 +++++++ lib/cmsis_core/cmsis_armclang.h | 1510 +++++++++++ lib/cmsis_core/cmsis_armclang_ltm.h | 1934 ++++++++++++++ lib/cmsis_core/cmsis_compiler.h | 303 +++ lib/cmsis_core/cmsis_gcc.h | 2217 +++++++++++++++++ lib/cmsis_core/cmsis_iccarm.h | 1008 ++++++++ lib/cmsis_core/cmsis_tiarmclang.h | 1510 +++++++++++ lib/cmsis_core/cmsis_version.h | 39 + lib/cmsis_core/core_cm4.h | 2170 ++++++++++++++++ lib/cmsis_core/mpu_armv7.h | 275 ++ lib/stm32wb.scons | 70 + lib/stm32wb_cmsis | 1 + lib/stm32wb_copro | 1 + lib/stm32wb_hal | 1 + scripts/assets.py | 25 +- scripts/flipper/assets/copro.py | 43 +- scripts/flipper/assets/coprobin.py | 2 +- 35 files changed, 12059 insertions(+), 189 deletions(-) delete mode 160000 lib/STM32CubeWB delete mode 100644 lib/STM32CubeWB.scons create mode 100644 lib/cmsis_core/cmsis_armcc.h create mode 100644 lib/cmsis_core/cmsis_armclang.h create mode 100644 lib/cmsis_core/cmsis_armclang_ltm.h create mode 100644 lib/cmsis_core/cmsis_compiler.h create mode 100644 lib/cmsis_core/cmsis_gcc.h create mode 100644 lib/cmsis_core/cmsis_iccarm.h create mode 100644 lib/cmsis_core/cmsis_tiarmclang.h create mode 100644 lib/cmsis_core/cmsis_version.h create mode 100644 lib/cmsis_core/core_cm4.h create mode 100644 lib/cmsis_core/mpu_armv7.h create mode 100644 lib/stm32wb.scons create mode 160000 lib/stm32wb_cmsis create mode 160000 lib/stm32wb_copro create mode 160000 lib/stm32wb_hal diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c1684aa99..bed54dfa0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -56,7 +56,7 @@ # Lib /lib/ST25RFAL002/ @skotopes @DrZlo13 @hedger @gornekich -/lib/STM32CubeWB/ @skotopes @DrZlo13 @hedger @gornekich +/lib/stm32wb_copro/ @skotopes @DrZlo13 @hedger @gornekich /lib/digital_signal/ @skotopes @DrZlo13 @hedger @gornekich /lib/infrared/ @skotopes @DrZlo13 @hedger @gsurkov /lib/lfrfid/ @skotopes @DrZlo13 @hedger @nminaylov diff --git a/.gitmodules b/.gitmodules index 3a15177bd..671e7e2c4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/mlib"] path = lib/mlib url = https://github.com/P-p-H-d/mlib.git -[submodule "lib/STM32CubeWB"] - path = lib/STM32CubeWB - url = https://github.com/Flipper-Zero/STM32CubeWB.git [submodule "lib/littlefs"] path = lib/littlefs url = https://github.com/littlefs-project/littlefs.git @@ -34,3 +31,12 @@ [submodule "lib/heatshrink"] path = lib/heatshrink url = https://github.com/flipperdevices/heatshrink.git +[submodule "lib/st_cmsis_device_wb"] + path = lib/stm32wb_cmsis + url = https://github.com/STMicroelectronics/cmsis_device_wb +[submodule "lib/stm32wbxx_hal_driver"] + path = lib/stm32wb_hal + url = https://github.com/STMicroelectronics/stm32wbxx_hal_driver +[submodule "lib/stm32wb_copro"] + path = lib/stm32wb_copro + url = https://github.com/flipperdevices/stm32wb_copro.git diff --git a/.pvsoptions b/.pvsoptions index 6b22aed76..b25d4633e 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/external/dap_link/lib/free-dap +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/external/dap_link/lib/free-dap diff --git a/documentation/Doxyfile b/documentation/Doxyfile index 9611e7f1a..bb43ce8a7 100644 --- a/documentation/Doxyfile +++ b/documentation/Doxyfile @@ -929,7 +929,9 @@ RECURSIVE = YES EXCLUDE = \ lib/mlib \ - lib/STM32CubeWB \ + lib/stm32wb_cmsis \ + lib/stm32wb_copro \ + lib/stm32wb_hal_driver \ lib/littlefs \ lib/nanopb \ assets/protobuf \ diff --git a/documentation/OTA.md b/documentation/OTA.md index 9d09c0f7c..799548f4d 100644 --- a/documentation/OTA.md +++ b/documentation/OTA.md @@ -133,7 +133,7 @@ For example, to build a package only for installing BLE FULL stack: scripts/update.py generate \ -t f7 -d r13.3_full -v "BLE FULL 13.3" \ --stage dist/f7/flipper-z-f7-updater-*.bin \ - --radio lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_BLE_Stack_full_fw.bin \ + --radio lib/stm32wb_copro/firmware/stm32wb5x_BLE_Stack_full_fw.bin \ --radiotype ble_full ``` diff --git a/fbt b/fbt index efe625f03..ef41cc056 100755 --- a/fbt +++ b/fbt @@ -5,6 +5,7 @@ set -eu; # private variables +N_GIT_THREADS="$(getconf _NPROCESSORS_ONLN)"; SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; SCONS_DEFAULT_FLAGS="--warn=target-not-built"; SCONS_EP="python3 -m SCons"; @@ -28,7 +29,7 @@ if [ -z "$FBT_NO_SYNC" ]; then echo "\".git\" directory not found, please clone repo via \"git clone\""; exit 1; fi - git submodule update --init --depth 1; + git submodule update --init --depth 1 --jobs "$N_GIT_THREADS"; fi $SCONS_EP $SCONS_DEFAULT_FLAGS "$@" diff --git a/fbt.cmd b/fbt.cmd index 6e839c778..03e4ec3d0 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -5,7 +5,7 @@ set SCONS_EP=python -m SCons if [%FBT_NO_SYNC%] == [] ( if exist ".git" ( - git submodule update --init --depth 1 + git submodule update --init --depth 1 --jobs %NUMBER_OF_PROCESSORS% ) else ( echo Not in a git repo, please clone with "git clone" exit /b 1 diff --git a/fbt_options.py b/fbt_options.py index 4fd7ef496..d05b882a0 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -19,10 +19,10 @@ DIST_SUFFIX = "local" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" -# Must match lib/STM32CubeWB version +# Must match lib/stm32wb_copro version COPRO_CUBE_VERSION = "1.15.0" -COPRO_CUBE_DIR = "lib/STM32CubeWB" +COPRO_CUBE_DIR = "lib/stm32wb_copro" # Default radio stack COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" @@ -33,12 +33,7 @@ COPRO_STACK_TYPE = "ble_light" COPRO_STACK_ADDR = "0x0" # If you override COPRO_CUBE_DIR on commandline, override this as well -COPRO_STACK_BIN_DIR = posixpath.join( - COPRO_CUBE_DIR, - "Projects", - "STM32WB_Copro_Wireless_Binaries", - "STM32WB5x", -) +COPRO_STACK_BIN_DIR = posixpath.join(COPRO_CUBE_DIR, "firmware") # Supported toolchain versions FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) diff --git a/firmware/SConscript b/firmware/SConscript index fa96b0adf..8d8789e72 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -7,7 +7,7 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") libenv.Append( CPPPATH=[ - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + "#/lib/stm32wb_copro/wpan/interface/patterns/ble_thread/tl", ] ) libenv.ApplyLibFlags() diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index f83f6405b..8db084e2f 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -78,33 +78,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_adc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_bus.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_comp.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_cortex.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crs.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dma.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dmamux.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_exti.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_gpio.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_hsem.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_i2c.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_ipcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_iwdg.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lptim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lpuart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pka.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pwr.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rng.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rtc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_spi.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_system.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_tim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_usart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -156,6 +129,33 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_cortex.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_crc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_crs.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_dma.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_dmamux.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_exti.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_gpio.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_hsem.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_i2c.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_ipcc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_iwdg.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_lptim.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_lpuart.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_pka.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_pwr.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rcc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rng.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rtc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_spi.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_system.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, @@ -201,8 +201,8 @@ Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef* Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef* Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*" Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef* -Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef* -Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*" +Function,-,LL_I2C_DeInit,ErrorStatus,const I2C_TypeDef* +Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, const LL_I2C_InitTypeDef*" Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* Function,-,LL_Init1msTick,void,uint32_t Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* diff --git a/firmware/targets/f18/target.json b/firmware/targets/f18/target.json index f1963fb01..14d395d22 100644 --- a/firmware/targets/f18/target.json +++ b/firmware/targets/f18/target.json @@ -14,7 +14,7 @@ "flipper18", "furi", "freertos", - "stm32cubewb", + "stm32wb", "hwdrivers", "fatfs", "littlefs", @@ -53,4 +53,4 @@ "infrared", "st25rfal002" ] -} +} \ No newline at end of file diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 8a4e06303..643835608 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -84,33 +84,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_adc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_bus.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_comp.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_cortex.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crs.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dma.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dmamux.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_exti.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_gpio.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_hsem.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_i2c.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_ipcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_iwdg.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lptim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lpuart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pka.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pwr.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rng.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rtc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_spi.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_system.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_tim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_usart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -175,6 +148,33 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_cortex.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_crc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_crs.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_dma.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_dmamux.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_exti.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_gpio.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_hsem.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_i2c.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_ipcc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_iwdg.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_lptim.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_lpuart.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_pka.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_pwr.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rcc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rng.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_rtc.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_spi.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_system.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, +Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, Header,+,lib/subghz/blocks/const.h,, Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, @@ -233,8 +233,8 @@ Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef* Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef* Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*" Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef* -Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef* -Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*" +Function,-,LL_I2C_DeInit,ErrorStatus,const I2C_TypeDef* +Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, const LL_I2C_InitTypeDef*" Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* Function,-,LL_Init1msTick,void,uint32_t Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 464d88d95..94d269345 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -27,7 +27,7 @@ #define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) -/* lib/STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c +/* STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c * ProcessSingleFlashOperation, quote: > In most BLE application, the flash should not be blocked by the CPU2 longer than FLASH_TIMEOUT_VALUE (1000ms) > However, it could be that for some marginal application, this time is longer. diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 14bb1cd0c..4d97ae7d7 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -20,7 +20,7 @@ "flipper7", "furi", "freertos", - "stm32cubewb", + "stm32wb", "hwdrivers", "fatfs", "littlefs", @@ -43,4 +43,4 @@ "flipperformat", "toolbox" ] -} +} \ No newline at end of file diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 82dcb74c7..884a0b8c0 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -19,7 +19,9 @@ - `one_wire` - One wire library - `qrcode` - Qr code generator library - `ST25RFAL002` - ST253916 driver and NFC hal -- `STM32CubeWB` - STM32WB series cube package +- `stm32wb_cmsis` - STM32WB series CMSIS component +- `stm32wb_copro` - STM32WB Coprocessor fimrware + WPAN library +- `stm32wb_hal_driver` - STM32WB series HAL - `subghz` - SubGhz library - `toolbox` - Toolbox of things that we are using but don't place in core - `u8g2` - Graphics library that we use to draw GUI diff --git a/lib/SConscript b/lib/SConscript index f5d4689f1..b8a36c872 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -76,7 +76,7 @@ env.Append( libs = env.BuildModules( [ - "STM32CubeWB", + "stm32wb", "freertos", "print", "microtar", diff --git a/lib/STM32CubeWB b/lib/STM32CubeWB deleted file mode 160000 index c4cec8ae5..000000000 --- a/lib/STM32CubeWB +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c4cec8ae57a79e949a184cd0b4117a008a0a25a7 diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons deleted file mode 100644 index b0e55f82e..000000000 --- a/lib/STM32CubeWB.scons +++ /dev/null @@ -1,72 +0,0 @@ -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", - "#/lib/STM32CubeWB/Drivers/CMSIS/Include", - "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", - ], - CPPDEFINES=[ - "STM32WB", - "STM32WB55xx", - "USE_FULL_ASSERT", - "USE_FULL_LL_DRIVER", - ], - SDK_HEADERS=env.GlobRecursive( - "*_ll_*.h", - Dir("STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/"), - exclude="*usb.h", - ), -) - -if env["RAM_EXEC"]: - env.Append( - CPPDEFINES=[ - "VECT_TAB_SRAM", - ], - ) - - -libenv = env.Clone(FW_LIB_NAME="stm32cubewb") -libenv.Append( - CPPPATH=[ - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", - "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", - ] -) -libenv.ApplyLibFlags() - -sources = libenv.GlobRecursive( - "*_ll_*.c", "STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" -) -sources += Glob( - "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", - source=True, -) -sources += Glob( - "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/*_tl*.c", - source=True, -) -sources += [ - "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/otp.c", - "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/stm_list.c", -] - - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/cmsis_core/cmsis_armcc.h b/lib/cmsis_core/cmsis_armcc.h new file mode 100644 index 000000000..2edff5af5 --- /dev/null +++ b/lib/cmsis_core/cmsis_armcc.h @@ -0,0 +1,894 @@ +/**************************************************************************//** + * @file cmsis_armcc.h + * @brief CMSIS compiler ARMCC (Arm Compiler 5) header file + * @version V5.4.0 + * @date 20. January 2023 + ******************************************************************************/ +/* + * Copyright (c) 2009-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_ARMCC_H +#define __CMSIS_ARMCC_H + + +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 400677) + #error "Please use Arm Compiler Toolchain V4.0.677 or later!" +#endif + +/* CMSIS compiler control architecture macros */ +#if ((defined (__TARGET_ARCH_6_M ) && (__TARGET_ARCH_6_M == 1)) || \ + (defined (__TARGET_ARCH_6S_M ) && (__TARGET_ARCH_6S_M == 1)) ) + #define __ARM_ARCH_6M__ 1 +#endif + +#if (defined (__TARGET_ARCH_7_M ) && (__TARGET_ARCH_7_M == 1)) + #define __ARM_ARCH_7M__ 1 +#endif + +#if (defined (__TARGET_ARCH_7E_M) && (__TARGET_ARCH_7E_M == 1)) + #define __ARM_ARCH_7EM__ 1 +#endif + + /* __ARM_ARCH_8M_BASE__ not applicable */ + /* __ARM_ARCH_8M_MAIN__ not applicable */ + /* __ARM_ARCH_8_1M_MAIN__ not applicable */ + +/* CMSIS compiler control DSP macros */ +#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + #define __ARM_FEATURE_DSP 1 +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE static __forceinline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __declspec(noreturn) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed)) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT __packed struct +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION __packed union +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #define __UNALIGNED_UINT32(x) (*((__packed uint32_t *)(x))) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #define __UNALIGNED_UINT16_WRITE(addr, val) ((*((__packed uint16_t *)(addr))) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #define __UNALIGNED_UINT16_READ(addr) (*((const __packed uint16_t *)(addr))) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #define __UNALIGNED_UINT32_WRITE(addr, val) ((*((__packed uint32_t *)(addr))) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #define __UNALIGNED_UINT32_READ(addr) (*((const __packed uint32_t *)(addr))) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __memory_changed() +#endif +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"), zero_init)) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + +/* ######################### Startup and Lowlevel Init ######################## */ + +#ifndef __PROGRAM_START +#define __PROGRAM_START __main +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP Image$$ARM_LIB_STACK$$ZI$$Limit +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT Image$$ARM_LIB_STACK$$ZI$$Base +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __Vectors +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section("RESET"))) +#endif + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __nop + + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __isb(0xF) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __dsb(0xF) + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __dmb(0xF) + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV __rev + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value) +{ + rev16 r0, r0 + bx lr +} +#endif + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int16_t __REVSH(int16_t value) +{ + revsh r0, r0 + bx lr +} +#endif + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +#define __ROR __ror + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __breakpoint(value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + #define __RBIT __rbit +#else +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value != 0U; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ + return result; +} +#endif + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ __clz + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr)) +#else + #define __LDREXB(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint8_t ) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXH(ptr) ((uint16_t) __ldrex(ptr)) +#else + #define __LDREXH(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint16_t) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr)) +#else + #define __LDREXW(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint32_t ) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXB(value, ptr) __strex(value, ptr) +#else + #define __STREXB(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXH(value, ptr) __strex(value, ptr) +#else + #define __STREXH(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXW(value, ptr) __strex(value, ptr) +#else + #define __STREXW(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __clrex + + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint32_t value) +{ + rrx r0, r0 + bx lr +} +#endif + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDRBT(ptr) ((uint8_t ) __ldrt(ptr)) + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDRHT(ptr) ((uint16_t) __ldrt(ptr)) + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDRT(ptr) ((uint32_t ) __ldrt(ptr)) + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRBT(value, ptr) __strt(value, ptr) + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRHT(value, ptr) __strt(value, ptr) + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRT(value, ptr) __strt(value, ptr) + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__attribute__((always_inline)) __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +/* intrinsic void __enable_irq(); */ + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +/* intrinsic void __disable_irq(); */ + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_INLINE uint32_t __get_CONTROL(void) +{ + register uint32_t __regControl __ASM("control"); + return(__regControl); +} + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + register uint32_t __regControl __ASM("control"); + __regControl = control; + __ISB(); +} + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_INLINE uint32_t __get_IPSR(void) +{ + register uint32_t __regIPSR __ASM("ipsr"); + return(__regIPSR); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_INLINE uint32_t __get_APSR(void) +{ + register uint32_t __regAPSR __ASM("apsr"); + return(__regAPSR); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_INLINE uint32_t __get_xPSR(void) +{ + register uint32_t __regXPSR __ASM("xpsr"); + return(__regXPSR); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_INLINE uint32_t __get_PSP(void) +{ + register uint32_t __regProcessStackPointer __ASM("psp"); + return(__regProcessStackPointer); +} + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + register uint32_t __regProcessStackPointer __ASM("psp"); + __regProcessStackPointer = topOfProcStack; +} + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_INLINE uint32_t __get_MSP(void) +{ + register uint32_t __regMainStackPointer __ASM("msp"); + return(__regMainStackPointer); +} + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + register uint32_t __regMainStackPointer __ASM("msp"); + __regMainStackPointer = topOfMainStack; +} + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + register uint32_t __regPriMask __ASM("primask"); + return(__regPriMask); +} + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + register uint32_t __regPriMask __ASM("primask"); + __regPriMask = (priMask); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +#define __enable_fault_irq __enable_fiq + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +#define __disable_fault_irq __disable_fiq + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_INLINE uint32_t __get_BASEPRI(void) +{ + register uint32_t __regBasePri __ASM("basepri"); + return(__regBasePri); +} + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_INLINE void __set_BASEPRI(uint32_t basePri) +{ + register uint32_t __regBasePri __ASM("basepri"); + __regBasePri = (basePri & 0xFFU); +} + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_INLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + register uint32_t __regBasePriMax __ASM("basepri_max"); + __regBasePriMax = (basePri & 0xFFU); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_INLINE uint32_t __get_FAULTMASK(void) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + return(__regFaultMask); +} + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + __regFaultMask = (faultMask & (uint32_t)1U); +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ + + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__STATIC_INLINE uint32_t __get_FPSCR(void) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) + register uint32_t __regfpscr __ASM("fpscr"); + return(__regfpscr); +#else + return(0U); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) + register uint32_t __regfpscr __ASM("fpscr"); + __regfpscr = (fpscr); +#else + (void)fpscr; +#endif +} + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) + +#define __SADD8 __sadd8 +#define __QADD8 __qadd8 +#define __SHADD8 __shadd8 +#define __UADD8 __uadd8 +#define __UQADD8 __uqadd8 +#define __UHADD8 __uhadd8 +#define __SSUB8 __ssub8 +#define __QSUB8 __qsub8 +#define __SHSUB8 __shsub8 +#define __USUB8 __usub8 +#define __UQSUB8 __uqsub8 +#define __UHSUB8 __uhsub8 +#define __SADD16 __sadd16 +#define __QADD16 __qadd16 +#define __SHADD16 __shadd16 +#define __UADD16 __uadd16 +#define __UQADD16 __uqadd16 +#define __UHADD16 __uhadd16 +#define __SSUB16 __ssub16 +#define __QSUB16 __qsub16 +#define __SHSUB16 __shsub16 +#define __USUB16 __usub16 +#define __UQSUB16 __uqsub16 +#define __UHSUB16 __uhsub16 +#define __SASX __sasx +#define __QASX __qasx +#define __SHASX __shasx +#define __UASX __uasx +#define __UQASX __uqasx +#define __UHASX __uhasx +#define __SSAX __ssax +#define __QSAX __qsax +#define __SHSAX __shsax +#define __USAX __usax +#define __UQSAX __uqsax +#define __UHSAX __uhsax +#define __USAD8 __usad8 +#define __USADA8 __usada8 +#define __SSAT16 __ssat16 +#define __USAT16 __usat16 +#define __UXTB16 __uxtb16 +#define __UXTAB16 __uxtab16 +#define __SXTB16 __sxtb16 +#define __SXTAB16 __sxtab16 +#define __SMUAD __smuad +#define __SMUADX __smuadx +#define __SMLAD __smlad +#define __SMLADX __smladx +#define __SMLALD __smlald +#define __SMLALDX __smlaldx +#define __SMUSD __smusd +#define __SMUSDX __smusdx +#define __SMLSD __smlsd +#define __SMLSDX __smlsdx +#define __SMLSLD __smlsld +#define __SMLSLDX __smlsldx +#define __SEL __sel +#define __QADD __qadd +#define __QSUB __qsub + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ + ((int64_t)(ARG3) << 32U) ) >> 32U)) + +#define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) + +#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) + +#endif /* ((defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) ) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCC_H */ diff --git a/lib/cmsis_core/cmsis_armclang.h b/lib/cmsis_core/cmsis_armclang.h new file mode 100644 index 000000000..139923dab --- /dev/null +++ b/lib/cmsis_core/cmsis_armclang.h @@ -0,0 +1,1510 @@ +/**************************************************************************//** + * @file cmsis_armclang.h + * @brief CMSIS compiler armclang (Arm Compiler 6) header file + * @version V5.5.0 + * @date 20. January 2023 + ******************************************************************************/ +/* + * Copyright (c) 2009-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ + +#ifndef __CMSIS_ARMCLANG_H +#define __CMSIS_ARMCLANG_H + +#pragma clang system_header /* treat file as system include file */ + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __ASM volatile("":::"memory") +#endif +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + + +/* ######################### Startup and Lowlevel Init ######################## */ + +#ifndef __PROGRAM_START +#define __PROGRAM_START __main +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP Image$$ARM_LIB_STACK$$ZI$$Limit +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT Image$$ARM_LIB_STACK$$ZI$$Base +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __Vectors +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section("RESET"))) +#endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#ifndef __STACK_SEAL +#define __STACK_SEAL Image$$STACKSEAL$$ZI$$Base +#endif + +#ifndef __TZ_STACK_SEAL_SIZE +#define __TZ_STACK_SEAL_SIZE 8U +#endif + +#ifndef __TZ_STACK_SEAL_VALUE +#define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL +#endif + + +__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { + *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; +} +#endif + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __builtin_arm_nop + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __builtin_arm_wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __builtin_arm_wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __builtin_arm_sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __builtin_arm_isb(0xF) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __builtin_arm_dsb(0xF) + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __builtin_arm_dmb(0xF) + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV(value) __builtin_bswap32(value) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV16(value) __ROR(__REV(value), 16) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REVSH(value) (int16_t)__builtin_bswap16(value) + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __RBIT __builtin_arm_rbit + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDREXB (uint8_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDREXH (uint16_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDREXW (uint32_t)__builtin_arm_ldrex + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXB (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXH (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXW (uint32_t)__builtin_arm_strex + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __builtin_arm_clrex + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __builtin_arm_ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __builtin_arm_usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDAEXB (uint8_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDAEXH (uint16_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDAEX (uint32_t)__builtin_arm_ldaex + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXB (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXH (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEX (uint32_t)__builtin_arm_stlex + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** @}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} +#endif + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} +#endif + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); + __ISB(); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); + __ISB(); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr +#else +#define __get_FPSCR() ((uint32_t)0U) +#endif + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __set_FPSCR __builtin_arm_set_fpscr +#else +#define __set_FPSCR(fpscr) ((void)(fpscr)) +#endif + + +/** @} end of CMSIS_Core_RegAccFunctions */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +#define __SADD8 __builtin_arm_sadd8 +#define __QADD8 __builtin_arm_qadd8 +#define __SHADD8 __builtin_arm_shadd8 +#define __UADD8 __builtin_arm_uadd8 +#define __UQADD8 __builtin_arm_uqadd8 +#define __UHADD8 __builtin_arm_uhadd8 +#define __SSUB8 __builtin_arm_ssub8 +#define __QSUB8 __builtin_arm_qsub8 +#define __SHSUB8 __builtin_arm_shsub8 +#define __USUB8 __builtin_arm_usub8 +#define __UQSUB8 __builtin_arm_uqsub8 +#define __UHSUB8 __builtin_arm_uhsub8 +#define __SADD16 __builtin_arm_sadd16 +#define __QADD16 __builtin_arm_qadd16 +#define __SHADD16 __builtin_arm_shadd16 +#define __UADD16 __builtin_arm_uadd16 +#define __UQADD16 __builtin_arm_uqadd16 +#define __UHADD16 __builtin_arm_uhadd16 +#define __SSUB16 __builtin_arm_ssub16 +#define __QSUB16 __builtin_arm_qsub16 +#define __SHSUB16 __builtin_arm_shsub16 +#define __USUB16 __builtin_arm_usub16 +#define __UQSUB16 __builtin_arm_uqsub16 +#define __UHSUB16 __builtin_arm_uhsub16 +#define __SASX __builtin_arm_sasx +#define __QASX __builtin_arm_qasx +#define __SHASX __builtin_arm_shasx +#define __UASX __builtin_arm_uasx +#define __UQASX __builtin_arm_uqasx +#define __UHASX __builtin_arm_uhasx +#define __SSAX __builtin_arm_ssax +#define __QSAX __builtin_arm_qsax +#define __SHSAX __builtin_arm_shsax +#define __USAX __builtin_arm_usax +#define __UQSAX __builtin_arm_uqsax +#define __UHSAX __builtin_arm_uhsax +#define __USAD8 __builtin_arm_usad8 +#define __USADA8 __builtin_arm_usada8 +#define __SSAT16 __builtin_arm_ssat16 +#define __USAT16 __builtin_arm_usat16 +#define __UXTB16 __builtin_arm_uxtb16 +#define __UXTAB16 __builtin_arm_uxtab16 +#define __SXTB16 __builtin_arm_sxtb16 +#define __SXTAB16 __builtin_arm_sxtab16 +#define __SMUAD __builtin_arm_smuad +#define __SMUADX __builtin_arm_smuadx +#define __SMLAD __builtin_arm_smlad +#define __SMLADX __builtin_arm_smladx +#define __SMLALD __builtin_arm_smlald +#define __SMLALDX __builtin_arm_smlaldx +#define __SMUSD __builtin_arm_smusd +#define __SMUSDX __builtin_arm_smusdx +#define __SMLSD __builtin_arm_smlsd +#define __SMLSDX __builtin_arm_smlsdx +#define __SMLSLD __builtin_arm_smlsld +#define __SMLSLDX __builtin_arm_smlsldx +#define __SEL __builtin_arm_sel +#define __QADD __builtin_arm_qadd +#define __QSUB __builtin_arm_qsub + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) + +#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/** @} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCLANG_H */ diff --git a/lib/cmsis_core/cmsis_armclang_ltm.h b/lib/cmsis_core/cmsis_armclang_ltm.h new file mode 100644 index 000000000..477136e84 --- /dev/null +++ b/lib/cmsis_core/cmsis_armclang_ltm.h @@ -0,0 +1,1934 @@ +/**************************************************************************//** + * @file cmsis_armclang_ltm.h + * @brief CMSIS compiler armclang (Arm Compiler 6) header file + * @version V1.6.0 + * @date 20. January 2023 + ******************************************************************************/ +/* + * Copyright (c) 2018-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ + +#ifndef __CMSIS_ARMCLANG_H +#define __CMSIS_ARMCLANG_H + +#pragma clang system_header /* treat file as system include file */ + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __ASM volatile("":::"memory") +#endif +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + +/* ######################### Startup and Lowlevel Init ######################## */ + +#ifndef __PROGRAM_START +#define __PROGRAM_START __main +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP Image$$ARM_LIB_STACK$$ZI$$Limit +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT Image$$ARM_LIB_STACK$$ZI$$Base +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __Vectors +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section("RESET"))) +#endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#ifndef __STACK_SEAL +#define __STACK_SEAL Image$$STACKSEAL$$ZI$$Base +#endif + +#ifndef __TZ_STACK_SEAL_SIZE +#define __TZ_STACK_SEAL_SIZE 8U +#endif + +#ifndef __TZ_STACK_SEAL_VALUE +#define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL +#endif + + +__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { + *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; +} +#endif + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __builtin_arm_nop + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __builtin_arm_wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __builtin_arm_wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __builtin_arm_sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __builtin_arm_isb(0xF) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __builtin_arm_dsb(0xF) + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __builtin_arm_dmb(0xF) + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV(value) __builtin_bswap32(value) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV16(value) __ROR(__REV(value), 16) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REVSH(value) (int16_t)__builtin_bswap16(value) + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __RBIT __builtin_arm_rbit + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDREXB (uint8_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDREXH (uint16_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDREXW (uint32_t)__builtin_arm_ldrex + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXB (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXH (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXW (uint32_t)__builtin_arm_strex + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __builtin_arm_clrex + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __builtin_arm_ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __builtin_arm_usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDAEXB (uint8_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDAEXH (uint16_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDAEX (uint32_t)__builtin_arm_ldaex + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXB (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXH (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEX (uint32_t)__builtin_arm_stlex + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} +#endif + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} +#endif + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); + __ISB(); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); + __ISB(); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr +#else +#define __get_FPSCR() ((uint32_t)0U) +#endif + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __set_FPSCR __builtin_arm_set_fpscr +#else +#define __set_FPSCR(x) ((void)(x)) +#endif + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1,ARG2) \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +#define __USAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) + +#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCLANG_H */ diff --git a/lib/cmsis_core/cmsis_compiler.h b/lib/cmsis_core/cmsis_compiler.h new file mode 100644 index 000000000..192f9b7c9 --- /dev/null +++ b/lib/cmsis_core/cmsis_compiler.h @@ -0,0 +1,303 @@ +/**************************************************************************//** + * @file cmsis_compiler.h + * @brief CMSIS compiler generic header file + * @version V5.3.0 + * @date 04. April 2023 + ******************************************************************************/ +/* + * Copyright (c) 2009-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_COMPILER_H +#define __CMSIS_COMPILER_H + +#include + +/* + * Arm Compiler 4/5 + */ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + + +/* + * Arm Compiler 6.6 LTM (armclang) + */ +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100) + #include "cmsis_armclang_ltm.h" + + /* + * Arm Compiler above 6.10.1 (armclang) + */ +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) + #include "cmsis_armclang.h" + +/* + * TI Arm Clang Compiler (tiarmclang) + */ +#elif defined (__ti__) + #include "cmsis_tiarmclang.h" + +/* + * GNU Compiler + */ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + + +/* + * IAR Compiler + */ +#elif defined ( __ICCARM__ ) + #include + + +/* + * TI Arm Compiler (armcl) + */ +#elif defined ( __TI_ARM__ ) + #include + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __attribute__((packed)) + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed)) + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed)) + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) + #endif + #ifndef __RESTRICT + #define __RESTRICT __restrict + #endif + #ifndef __COMPILER_BARRIER + #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. + #define __COMPILER_BARRIER() (void)0 + #endif + #ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) + #endif + #ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) + #endif + +/* + * TASKING Compiler + */ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __packed__ + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __packed__ + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __packed__ + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __packed__ T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __align(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + #ifndef __COMPILER_BARRIER + #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. + #define __COMPILER_BARRIER() (void)0 + #endif + #ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) + #endif + #ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) + #endif + +/* + * COSMIC Compiler + */ +#elif defined ( __CSMC__ ) + #include + + #ifndef __ASM + #define __ASM _asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + // NO RETURN is automatically detected hence no warning here + #define __NO_RETURN + #endif + #ifndef __USED + #warning No compiler specific solution for __USED. __USED is ignored. + #define __USED + #endif + #ifndef __WEAK + #define __WEAK __weak + #endif + #ifndef __PACKED + #define __PACKED @packed + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT @packed struct + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION @packed union + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + @packed struct T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. + #define __ALIGNED(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + #ifndef __COMPILER_BARRIER + #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. + #define __COMPILER_BARRIER() (void)0 + #endif + #ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) + #endif + #ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) + #endif + +#else + #error Unknown compiler. +#endif + + +#endif /* __CMSIS_COMPILER_H */ + diff --git a/lib/cmsis_core/cmsis_gcc.h b/lib/cmsis_core/cmsis_gcc.h new file mode 100644 index 000000000..4f0762d6d --- /dev/null +++ b/lib/cmsis_core/cmsis_gcc.h @@ -0,0 +1,2217 @@ +/**************************************************************************//** + * @file cmsis_gcc.h + * @brief CMSIS compiler GCC header file + * @version V5.4.2 + * @date 17. December 2022 + ******************************************************************************/ +/* + * Copyright (c) 2009-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_GCC_H +#define __CMSIS_GCC_H + +/* ignore some GCC warnings */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +/* Fallback for __has_builtin */ +#ifndef __has_builtin + #define __has_builtin(x) (0) +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __ASM volatile("":::"memory") +#endif +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + +/* ######################### Startup and Lowlevel Init ######################## */ + +#ifndef __PROGRAM_START + +/** + \brief Initializes data and bss sections + \details This default implementations initialized all data and additional bss + sections relying on .copy.table and .zero.table specified properly + in the used linker script. + + */ +__STATIC_FORCEINLINE __NO_RETURN void __cmsis_start(void) +{ + extern void _start(void) __NO_RETURN; + + typedef struct __copy_table { + uint32_t const* src; + uint32_t* dest; + uint32_t wlen; + } __copy_table_t; + + typedef struct __zero_table { + uint32_t* dest; + uint32_t wlen; + } __zero_table_t; + + extern const __copy_table_t __copy_table_start__; + extern const __copy_table_t __copy_table_end__; + extern const __zero_table_t __zero_table_start__; + extern const __zero_table_t __zero_table_end__; + + for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) { + for(uint32_t i=0u; iwlen; ++i) { + pTable->dest[i] = pTable->src[i]; + } + } + + for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { + for(uint32_t i=0u; iwlen; ++i) { + pTable->dest[i] = 0u; + } + } + + _start(); +} + +#define __PROGRAM_START __cmsis_start +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP __StackTop +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT __StackLimit +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __Vectors +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section(".vectors"))) +#endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#ifndef __STACK_SEAL +#define __STACK_SEAL __StackSeal +#endif + +#ifndef __TZ_STACK_SEAL_SIZE +#define __TZ_STACK_SEAL_SIZE 8U +#endif + +#ifndef __TZ_STACK_SEAL_VALUE +#define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL +#endif + + +__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { + *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; +} +#endif + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP() __ASM volatile ("nop") + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI() __ASM volatile ("wfi":::"memory") + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE() __ASM volatile ("wfe":::"memory") + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV() __ASM volatile ("sev") + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +__STATIC_FORCEINLINE void __ISB(void) +{ + __ASM volatile ("isb 0xF":::"memory"); +} + + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); +} + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +__STATIC_FORCEINLINE void __DMB(void) +{ + __ASM volatile ("dmb 0xF":::"memory"); +} + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); +#else + uint32_t result; + + __ASM ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +#endif +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + + __ASM ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE int16_t __REVSH(int16_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + return (int16_t)__builtin_bswap16(value); +#else + int16_t result; + + __ASM ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +#endif +} + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + __ASM ("rbit %0, %1" : "=r" (result) : "r" (value) ); +#else + uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value != 0U; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ +#endif + return result; +} + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM GCC 7.3 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); + return(result); +} + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +__STATIC_FORCEINLINE void __CLREX(void) +{ + __ASM volatile ("clrex" ::: "memory"); +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT(ARG1, ARG2) \ +__extension__ \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM volatile ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ + __RES; \ + }) + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT(ARG1, ARG2) \ +__extension__ \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM volatile ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ + __RES; \ + }) + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexb %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexh %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaex %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return(result); +} + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexb %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); + return(result); +} + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexh %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); + return(result); +} + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlex %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); + return(result); +} + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); + __ISB(); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); + __ISB(); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__STATIC_FORCEINLINE uint32_t __get_FPSCR(void) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_get_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + return __builtin_arm_get_fpscr(); +#else + uint32_t result; + + __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + return(result); +#endif +#else + return(0U); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_set_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + __builtin_arm_set_fpscr(fpscr); +#else + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc", "memory"); +#endif +#else + (void)fpscr; +#endif +} + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1, ARG2) \ +__extension__ \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM volatile ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ + __RES; \ + }) + +#define __USAT16(ARG1, ARG2) \ +__extension__ \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM volatile ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) : "cc" ); \ + __RES; \ + }) + +__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTB16_RORn(uint32_t op1, uint32_t rotate) +{ + uint32_t result; + if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) { + __ASM volatile ("sxtb16 %0, %1, ROR %2" : "=r" (result) : "r" (op1), "i" (rotate) ); + } else { + result = __SXTB16(__ROR(op1, rotate)) ; + } + return result; +} + +__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTAB16_RORn(uint32_t op1, uint32_t op2, uint32_t rotate) +{ + uint32_t result; + if (__builtin_constant_p(rotate) && ((rotate == 8U) || (rotate == 16U) || (rotate == 24U))) { + __ASM volatile ("sxtab16 %0, %1, %2, ROR %3" : "=r" (result) : "r" (op1) , "r" (op2) , "i" (rotate)); + } else { + result = __SXTAB16(op1, __ROR(op2, rotate)); + } + return result; +} + + +__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +#define __PKHBT(ARG1,ARG2,ARG3) \ +__extension__ \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +#define __PKHTB(ARG1,ARG2,ARG3) \ +__extension__ \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + if (ARG3 == 0) \ + __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ + else \ + __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#pragma GCC diagnostic pop + +#endif /* __CMSIS_GCC_H */ diff --git a/lib/cmsis_core/cmsis_iccarm.h b/lib/cmsis_core/cmsis_iccarm.h new file mode 100644 index 000000000..47d6a859e --- /dev/null +++ b/lib/cmsis_core/cmsis_iccarm.h @@ -0,0 +1,1008 @@ +/**************************************************************************//** + * @file cmsis_iccarm.h + * @brief CMSIS compiler ICCARM (IAR Compiler for Arm) header file + * @version V5.4.0 + * @date 20. January 2023 + ******************************************************************************/ + +//------------------------------------------------------------------------------ +// +// Copyright (c) 2017-2021 IAR Systems +// Copyright (c) 2017-2023 Arm Limited. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License") +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//------------------------------------------------------------------------------ + + +#ifndef __CMSIS_ICCARM_H__ +#define __CMSIS_ICCARM_H__ + +#ifndef __ICCARM__ + #error This file should only be compiled by ICCARM +#endif + +#pragma system_include + +#define __IAR_FT _Pragma("inline=forced") __intrinsic + +#if (__VER__ >= 8000000) + #define __ICCARM_V8 1 +#else + #define __ICCARM_V8 0 +#endif + +#ifndef __ALIGNED + #if __ICCARM_V8 + #define __ALIGNED(x) __attribute__((aligned(x))) + #elif (__VER__ >= 7080000) + /* Needs IAR language extensions */ + #define __ALIGNED(x) __attribute__((aligned(x))) + #else + #warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored. + #define __ALIGNED(x) + #endif +#endif + + +/* Define compiler macros for CPU architecture, used in CMSIS 5. + */ +#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__ || __ARM_ARCH_8M_BASE__ || __ARM_ARCH_8M_MAIN__ +/* Macros already defined */ +#else + #if defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #elif defined(__ARM8M_BASELINE__) + #define __ARM_ARCH_8M_BASE__ 1 + #elif defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE == 'M' + #if __ARM_ARCH == 6 + #define __ARM_ARCH_6M__ 1 + #elif __ARM_ARCH == 7 + #if __ARM_FEATURE_DSP + #define __ARM_ARCH_7EM__ 1 + #else + #define __ARM_ARCH_7M__ 1 + #endif + #endif /* __ARM_ARCH */ + #endif /* __ARM_ARCH_PROFILE == 'M' */ +#endif + +/* Alternativ core deduction for older ICCARM's */ +#if !defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_7M__) && !defined(__ARM_ARCH_7EM__) && \ + !defined(__ARM_ARCH_8M_BASE__) && !defined(__ARM_ARCH_8M_MAIN__) + #if defined(__ARM6M__) && (__CORE__ == __ARM6M__) + #define __ARM_ARCH_6M__ 1 + #elif defined(__ARM7M__) && (__CORE__ == __ARM7M__) + #define __ARM_ARCH_7M__ 1 + #elif defined(__ARM7EM__) && (__CORE__ == __ARM7EM__) + #define __ARM_ARCH_7EM__ 1 + #elif defined(__ARM8M_BASELINE__) && (__CORE == __ARM8M_BASELINE__) + #define __ARM_ARCH_8M_BASE__ 1 + #elif defined(__ARM8M_MAINLINE__) && (__CORE == __ARM8M_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #elif defined(__ARM8EM_MAINLINE__) && (__CORE == __ARM8EM_MAINLINE__) + #define __ARM_ARCH_8M_MAIN__ 1 + #else + #error "Unknown target." + #endif +#endif + + + +#if defined(__ARM_ARCH_6M__) && __ARM_ARCH_6M__==1 + #define __IAR_M0_FAMILY 1 +#elif defined(__ARM_ARCH_8M_BASE__) && __ARM_ARCH_8M_BASE__==1 + #define __IAR_M0_FAMILY 1 +#else + #define __IAR_M0_FAMILY 0 +#endif + +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".noinit"))) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + +#ifndef __ASM + #define __ASM __asm +#endif + +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __ASM volatile("":::"memory") +#endif + +#ifndef __INLINE + #define __INLINE inline +#endif + +#ifndef __NO_RETURN + #if __ICCARM_V8 + #define __NO_RETURN __attribute__((__noreturn__)) + #else + #define __NO_RETURN _Pragma("object_attribute=__noreturn") + #endif +#endif + +#ifndef __PACKED + #if __ICCARM_V8 + #define __PACKED __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED __packed + #endif +#endif + +#ifndef __PACKED_STRUCT + #if __ICCARM_V8 + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED_STRUCT __packed struct + #endif +#endif + +#ifndef __PACKED_UNION + #if __ICCARM_V8 + #define __PACKED_UNION union __attribute__((packed, aligned(1))) + #else + /* Needs IAR language extensions */ + #define __PACKED_UNION __packed union + #endif +#endif + +#ifndef __RESTRICT + #if __ICCARM_V8 + #define __RESTRICT __restrict + #else + /* Needs IAR language extensions */ + #define __RESTRICT restrict + #endif +#endif + +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline +#endif + +#ifndef __FORCEINLINE + #define __FORCEINLINE _Pragma("inline=forced") +#endif + +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __FORCEINLINE __STATIC_INLINE +#endif + +#ifndef __UNALIGNED_UINT16_READ +#pragma language=save +#pragma language=extended +__IAR_FT uint16_t __iar_uint16_read(void const *ptr) +{ + return *(__packed uint16_t*)(ptr); +} +#pragma language=restore +#define __UNALIGNED_UINT16_READ(PTR) __iar_uint16_read(PTR) +#endif + + +#ifndef __UNALIGNED_UINT16_WRITE +#pragma language=save +#pragma language=extended +__IAR_FT void __iar_uint16_write(void const *ptr, uint16_t val) +{ + *(__packed uint16_t*)(ptr) = val;; +} +#pragma language=restore +#define __UNALIGNED_UINT16_WRITE(PTR,VAL) __iar_uint16_write(PTR,VAL) +#endif + +#ifndef __UNALIGNED_UINT32_READ +#pragma language=save +#pragma language=extended +__IAR_FT uint32_t __iar_uint32_read(void const *ptr) +{ + return *(__packed uint32_t*)(ptr); +} +#pragma language=restore +#define __UNALIGNED_UINT32_READ(PTR) __iar_uint32_read(PTR) +#endif + +#ifndef __UNALIGNED_UINT32_WRITE +#pragma language=save +#pragma language=extended +__IAR_FT void __iar_uint32_write(void const *ptr, uint32_t val) +{ + *(__packed uint32_t*)(ptr) = val;; +} +#pragma language=restore +#define __UNALIGNED_UINT32_WRITE(PTR,VAL) __iar_uint32_write(PTR,VAL) +#endif + +#ifndef __UNALIGNED_UINT32 /* deprecated */ +#pragma language=save +#pragma language=extended +__packed struct __iar_u32 { uint32_t v; }; +#pragma language=restore +#define __UNALIGNED_UINT32(PTR) (((struct __iar_u32 *)(PTR))->v) +#endif + +#ifndef __USED + #if __ICCARM_V8 + #define __USED __attribute__((used)) + #else + #define __USED _Pragma("__root") + #endif +#endif + +#undef __WEAK /* undo the definition from DLib_Defaults.h */ +#ifndef __WEAK + #if __ICCARM_V8 + #define __WEAK __attribute__((weak)) + #else + #define __WEAK _Pragma("__weak") + #endif +#endif + +#ifndef __PROGRAM_START +#define __PROGRAM_START __iar_program_start +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP CSTACK$$Limit +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT CSTACK$$Base +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __vector_table +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE @".intvec" +#endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#ifndef __STACK_SEAL +#define __STACK_SEAL STACKSEAL$$Base +#endif + +#ifndef __TZ_STACK_SEAL_SIZE +#define __TZ_STACK_SEAL_SIZE 8U +#endif + +#ifndef __TZ_STACK_SEAL_VALUE +#define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL +#endif + +__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { + *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; +} +#endif + +#ifndef __ICCARM_INTRINSICS_VERSION__ + #define __ICCARM_INTRINSICS_VERSION__ 0 +#endif + +#if __ICCARM_INTRINSICS_VERSION__ == 2 + + #if defined(__CLZ) + #undef __CLZ + #endif + #if defined(__REVSH) + #undef __REVSH + #endif + #if defined(__RBIT) + #undef __RBIT + #endif + #if defined(__SSAT) + #undef __SSAT + #endif + #if defined(__USAT) + #undef __USAT + #endif + + #include "iccarm_builtin.h" + + #define __disable_fault_irq __iar_builtin_disable_fiq + #define __disable_irq __iar_builtin_disable_interrupt + #define __enable_fault_irq __iar_builtin_enable_fiq + #define __enable_irq __iar_builtin_enable_interrupt + #define __arm_rsr __iar_builtin_rsr + #define __arm_wsr __iar_builtin_wsr + + + #define __get_APSR() (__arm_rsr("APSR")) + #define __get_BASEPRI() (__arm_rsr("BASEPRI")) + #define __get_CONTROL() (__arm_rsr("CONTROL")) + #define __get_FAULTMASK() (__arm_rsr("FAULTMASK")) + + #if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) + #define __get_FPSCR() (__arm_rsr("FPSCR")) + #define __set_FPSCR(VALUE) (__arm_wsr("FPSCR", (VALUE))) + #else + #define __get_FPSCR() ( 0 ) + #define __set_FPSCR(VALUE) ((void)VALUE) + #endif + + #define __get_IPSR() (__arm_rsr("IPSR")) + #define __get_MSP() (__arm_rsr("MSP")) + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + #define __get_MSPLIM() (0U) + #else + #define __get_MSPLIM() (__arm_rsr("MSPLIM")) + #endif + #define __get_PRIMASK() (__arm_rsr("PRIMASK")) + #define __get_PSP() (__arm_rsr("PSP")) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __get_PSPLIM() (0U) + #else + #define __get_PSPLIM() (__arm_rsr("PSPLIM")) + #endif + + #define __get_xPSR() (__arm_rsr("xPSR")) + + #define __set_BASEPRI(VALUE) (__arm_wsr("BASEPRI", (VALUE))) + #define __set_BASEPRI_MAX(VALUE) (__arm_wsr("BASEPRI_MAX", (VALUE))) + +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __arm_wsr("CONTROL", control); + __iar_builtin_ISB(); +} + + #define __set_FAULTMASK(VALUE) (__arm_wsr("FAULTMASK", (VALUE))) + #define __set_MSP(VALUE) (__arm_wsr("MSP", (VALUE))) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + #define __set_MSPLIM(VALUE) ((void)(VALUE)) + #else + #define __set_MSPLIM(VALUE) (__arm_wsr("MSPLIM", (VALUE))) + #endif + #define __set_PRIMASK(VALUE) (__arm_wsr("PRIMASK", (VALUE))) + #define __set_PSP(VALUE) (__arm_wsr("PSP", (VALUE))) + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __set_PSPLIM(VALUE) ((void)(VALUE)) + #else + #define __set_PSPLIM(VALUE) (__arm_wsr("PSPLIM", (VALUE))) + #endif + + #define __TZ_get_CONTROL_NS() (__arm_rsr("CONTROL_NS")) + +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __arm_wsr("CONTROL_NS", control); + __iar_builtin_ISB(); +} + + #define __TZ_get_PSP_NS() (__arm_rsr("PSP_NS")) + #define __TZ_set_PSP_NS(VALUE) (__arm_wsr("PSP_NS", (VALUE))) + #define __TZ_get_MSP_NS() (__arm_rsr("MSP_NS")) + #define __TZ_set_MSP_NS(VALUE) (__arm_wsr("MSP_NS", (VALUE))) + #define __TZ_get_SP_NS() (__arm_rsr("SP_NS")) + #define __TZ_set_SP_NS(VALUE) (__arm_wsr("SP_NS", (VALUE))) + #define __TZ_get_PRIMASK_NS() (__arm_rsr("PRIMASK_NS")) + #define __TZ_set_PRIMASK_NS(VALUE) (__arm_wsr("PRIMASK_NS", (VALUE))) + #define __TZ_get_BASEPRI_NS() (__arm_rsr("BASEPRI_NS")) + #define __TZ_set_BASEPRI_NS(VALUE) (__arm_wsr("BASEPRI_NS", (VALUE))) + #define __TZ_get_FAULTMASK_NS() (__arm_rsr("FAULTMASK_NS")) + #define __TZ_set_FAULTMASK_NS(VALUE)(__arm_wsr("FAULTMASK_NS", (VALUE))) + + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + #define __TZ_get_PSPLIM_NS() (0U) + #define __TZ_set_PSPLIM_NS(VALUE) ((void)(VALUE)) + #else + #define __TZ_get_PSPLIM_NS() (__arm_rsr("PSPLIM_NS")) + #define __TZ_set_PSPLIM_NS(VALUE) (__arm_wsr("PSPLIM_NS", (VALUE))) + #endif + + #define __TZ_get_MSPLIM_NS() (__arm_rsr("MSPLIM_NS")) + #define __TZ_set_MSPLIM_NS(VALUE) (__arm_wsr("MSPLIM_NS", (VALUE))) + + #define __NOP __iar_builtin_no_operation + + #define __CLZ __iar_builtin_CLZ + #define __CLREX __iar_builtin_CLREX + + #define __DMB __iar_builtin_DMB + #define __DSB __iar_builtin_DSB + #define __ISB __iar_builtin_ISB + + #define __LDREXB __iar_builtin_LDREXB + #define __LDREXH __iar_builtin_LDREXH + #define __LDREXW __iar_builtin_LDREX + + #define __RBIT __iar_builtin_RBIT + #define __REV __iar_builtin_REV + #define __REV16 __iar_builtin_REV16 + + __IAR_FT int16_t __REVSH(int16_t val) + { + return (int16_t) __iar_builtin_REVSH(val); + } + + #define __ROR __iar_builtin_ROR + #define __RRX __iar_builtin_RRX + + #define __SEV __iar_builtin_SEV + + #if !__IAR_M0_FAMILY + #define __SSAT __iar_builtin_SSAT + #endif + + #define __STREXB __iar_builtin_STREXB + #define __STREXH __iar_builtin_STREXH + #define __STREXW __iar_builtin_STREX + + #if !__IAR_M0_FAMILY + #define __USAT __iar_builtin_USAT + #endif + + #define __WFE __iar_builtin_WFE + #define __WFI __iar_builtin_WFI + + #if __ARM_MEDIA__ + #define __SADD8 __iar_builtin_SADD8 + #define __QADD8 __iar_builtin_QADD8 + #define __SHADD8 __iar_builtin_SHADD8 + #define __UADD8 __iar_builtin_UADD8 + #define __UQADD8 __iar_builtin_UQADD8 + #define __UHADD8 __iar_builtin_UHADD8 + #define __SSUB8 __iar_builtin_SSUB8 + #define __QSUB8 __iar_builtin_QSUB8 + #define __SHSUB8 __iar_builtin_SHSUB8 + #define __USUB8 __iar_builtin_USUB8 + #define __UQSUB8 __iar_builtin_UQSUB8 + #define __UHSUB8 __iar_builtin_UHSUB8 + #define __SADD16 __iar_builtin_SADD16 + #define __QADD16 __iar_builtin_QADD16 + #define __SHADD16 __iar_builtin_SHADD16 + #define __UADD16 __iar_builtin_UADD16 + #define __UQADD16 __iar_builtin_UQADD16 + #define __UHADD16 __iar_builtin_UHADD16 + #define __SSUB16 __iar_builtin_SSUB16 + #define __QSUB16 __iar_builtin_QSUB16 + #define __SHSUB16 __iar_builtin_SHSUB16 + #define __USUB16 __iar_builtin_USUB16 + #define __UQSUB16 __iar_builtin_UQSUB16 + #define __UHSUB16 __iar_builtin_UHSUB16 + #define __SASX __iar_builtin_SASX + #define __QASX __iar_builtin_QASX + #define __SHASX __iar_builtin_SHASX + #define __UASX __iar_builtin_UASX + #define __UQASX __iar_builtin_UQASX + #define __UHASX __iar_builtin_UHASX + #define __SSAX __iar_builtin_SSAX + #define __QSAX __iar_builtin_QSAX + #define __SHSAX __iar_builtin_SHSAX + #define __USAX __iar_builtin_USAX + #define __UQSAX __iar_builtin_UQSAX + #define __UHSAX __iar_builtin_UHSAX + #define __USAD8 __iar_builtin_USAD8 + #define __USADA8 __iar_builtin_USADA8 + #define __SSAT16 __iar_builtin_SSAT16 + #define __USAT16 __iar_builtin_USAT16 + #define __UXTB16 __iar_builtin_UXTB16 + #define __UXTAB16 __iar_builtin_UXTAB16 + #define __SXTB16 __iar_builtin_SXTB16 + #define __SXTAB16 __iar_builtin_SXTAB16 + #define __SMUAD __iar_builtin_SMUAD + #define __SMUADX __iar_builtin_SMUADX + #define __SMMLA __iar_builtin_SMMLA + #define __SMLAD __iar_builtin_SMLAD + #define __SMLADX __iar_builtin_SMLADX + #define __SMLALD __iar_builtin_SMLALD + #define __SMLALDX __iar_builtin_SMLALDX + #define __SMUSD __iar_builtin_SMUSD + #define __SMUSDX __iar_builtin_SMUSDX + #define __SMLSD __iar_builtin_SMLSD + #define __SMLSDX __iar_builtin_SMLSDX + #define __SMLSLD __iar_builtin_SMLSLD + #define __SMLSLDX __iar_builtin_SMLSLDX + #define __SEL __iar_builtin_SEL + #define __QADD __iar_builtin_QADD + #define __QSUB __iar_builtin_QSUB + #define __PKHBT __iar_builtin_PKHBT + #define __PKHTB __iar_builtin_PKHTB + #endif + +#else /* __ICCARM_INTRINSICS_VERSION__ == 2 */ + + #if __IAR_M0_FAMILY + /* Avoid clash between intrinsics.h and arm_math.h when compiling for Cortex-M0. */ + #define __CLZ __cmsis_iar_clz_not_active + #define __SSAT __cmsis_iar_ssat_not_active + #define __USAT __cmsis_iar_usat_not_active + #define __RBIT __cmsis_iar_rbit_not_active + #define __get_APSR __cmsis_iar_get_APSR_not_active + #endif + + + #if (!((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) )) + #define __get_FPSCR __cmsis_iar_get_FPSR_not_active + #define __set_FPSCR __cmsis_iar_set_FPSR_not_active + #endif + + #ifdef __INTRINSICS_INCLUDED + #error intrinsics.h is already included previously! + #endif + + #include + + #if __IAR_M0_FAMILY + /* Avoid clash between intrinsics.h and arm_math.h when compiling for Cortex-M0. */ + #undef __CLZ + #undef __SSAT + #undef __USAT + #undef __RBIT + #undef __get_APSR + + __STATIC_INLINE uint8_t __CLZ(uint32_t data) + { + if (data == 0U) { return 32U; } + + uint32_t count = 0U; + uint32_t mask = 0x80000000U; + + while ((data & mask) == 0U) + { + count += 1U; + mask = mask >> 1U; + } + return count; + } + + __STATIC_INLINE uint32_t __RBIT(uint32_t v) + { + uint8_t sc = 31U; + uint32_t r = v; + for (v >>= 1U; v; v >>= 1U) + { + r <<= 1U; + r |= v & 1U; + sc--; + } + return (r << sc); + } + + __STATIC_INLINE uint32_t __get_APSR(void) + { + uint32_t res; + __asm("MRS %0,APSR" : "=r" (res)); + return res; + } + + #endif + + #if (!((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) )) + #undef __get_FPSCR + #undef __set_FPSCR + #define __get_FPSCR() (0) + #define __set_FPSCR(VALUE) ((void)VALUE) + #endif + + #pragma diag_suppress=Pe940 + #pragma diag_suppress=Pe177 + + #define __enable_irq __enable_interrupt + #define __disable_irq __disable_interrupt + #define __NOP __no_operation + + #define __get_xPSR __get_PSR + + #if (!defined(__ARM_ARCH_6M__) || __ARM_ARCH_6M__==0) + + __IAR_FT uint32_t __LDREXW(uint32_t volatile *ptr) + { + return __LDREX((unsigned long *)ptr); + } + + __IAR_FT uint32_t __STREXW(uint32_t value, uint32_t volatile *ptr) + { + return __STREX(value, (unsigned long *)ptr); + } + #endif + + + /* __CORTEX_M is defined in core_cm0.h, core_cm3.h and core_cm4.h. */ + #if (__CORTEX_M >= 0x03) + + __IAR_FT uint32_t __RRX(uint32_t value) + { + uint32_t result; + __ASM volatile("RRX %0, %1" : "=r"(result) : "r" (value)); + return(result); + } + + __IAR_FT void __set_BASEPRI_MAX(uint32_t value) + { + __asm volatile("MSR BASEPRI_MAX,%0"::"r" (value)); + } + + + #define __enable_fault_irq __enable_fiq + #define __disable_fault_irq __disable_fiq + + + #endif /* (__CORTEX_M >= 0x03) */ + + __IAR_FT uint32_t __ROR(uint32_t op1, uint32_t op2) + { + return (op1 >> op2) | (op1 << ((sizeof(op1)*8)-op2)); + } + + #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + + __IAR_FT uint32_t __get_MSPLIM(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,MSPLIM" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __set_MSPLIM(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR MSPLIM,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __get_PSPLIM(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,PSPLIM" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __set_PSPLIM(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR PSPLIM,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __TZ_get_CONTROL_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,CONTROL_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_CONTROL_NS(uint32_t value) + { + __asm volatile("MSR CONTROL_NS,%0" :: "r" (value)); + __iar_builtin_ISB(); + } + + __IAR_FT uint32_t __TZ_get_PSP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,PSP_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_PSP_NS(uint32_t value) + { + __asm volatile("MSR PSP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_MSP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,MSP_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_MSP_NS(uint32_t value) + { + __asm volatile("MSR MSP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_SP_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,SP_NS" : "=r" (res)); + return res; + } + __IAR_FT void __TZ_set_SP_NS(uint32_t value) + { + __asm volatile("MSR SP_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_PRIMASK_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,PRIMASK_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_PRIMASK_NS(uint32_t value) + { + __asm volatile("MSR PRIMASK_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_BASEPRI_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,BASEPRI_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_BASEPRI_NS(uint32_t value) + { + __asm volatile("MSR BASEPRI_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_FAULTMASK_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,FAULTMASK_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_FAULTMASK_NS(uint32_t value) + { + __asm volatile("MSR FAULTMASK_NS,%0" :: "r" (value)); + } + + __IAR_FT uint32_t __TZ_get_PSPLIM_NS(void) + { + uint32_t res; + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + res = 0U; + #else + __asm volatile("MRS %0,PSPLIM_NS" : "=r" (res)); + #endif + return res; + } + + __IAR_FT void __TZ_set_PSPLIM_NS(uint32_t value) + { + #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE ) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)value; + #else + __asm volatile("MSR PSPLIM_NS,%0" :: "r" (value)); + #endif + } + + __IAR_FT uint32_t __TZ_get_MSPLIM_NS(void) + { + uint32_t res; + __asm volatile("MRS %0,MSPLIM_NS" : "=r" (res)); + return res; + } + + __IAR_FT void __TZ_set_MSPLIM_NS(uint32_t value) + { + __asm volatile("MSR MSPLIM_NS,%0" :: "r" (value)); + } + + #endif /* __ARM_ARCH_8M_MAIN__ or __ARM_ARCH_8M_BASE__ */ + +#endif /* __ICCARM_INTRINSICS_VERSION__ == 2 */ + +#define __BKPT(value) __asm volatile ("BKPT %0" : : "i"(value)) + +#if __IAR_M0_FAMILY + __STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat) + { + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; + } + + __STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat) + { + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; + } +#endif + +#if (__CORTEX_M >= 0x03) /* __CORTEX_M is defined in core_cm0.h, core_cm3.h and core_cm4.h. */ + + __IAR_FT uint8_t __LDRBT(volatile uint8_t *addr) + { + uint32_t res; + __ASM volatile ("LDRBT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDRHT(volatile uint16_t *addr) + { + uint32_t res; + __ASM volatile ("LDRHT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDRT(volatile uint32_t *addr) + { + uint32_t res; + __ASM volatile ("LDRT %0, [%1]" : "=r" (res) : "r" (addr) : "memory"); + return res; + } + + __IAR_FT void __STRBT(uint8_t value, volatile uint8_t *addr) + { + __ASM volatile ("STRBT %1, [%0]" : : "r" (addr), "r" ((uint32_t)value) : "memory"); + } + + __IAR_FT void __STRHT(uint16_t value, volatile uint16_t *addr) + { + __ASM volatile ("STRHT %1, [%0]" : : "r" (addr), "r" ((uint32_t)value) : "memory"); + } + + __IAR_FT void __STRT(uint32_t value, volatile uint32_t *addr) + { + __ASM volatile ("STRT %1, [%0]" : : "r" (addr), "r" (value) : "memory"); + } + +#endif /* (__CORTEX_M >= 0x03) */ + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + + + __IAR_FT uint8_t __LDAB(volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAB %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDAH(volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAH %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDA(volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("LDA %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return res; + } + + __IAR_FT void __STLB(uint8_t value, volatile uint8_t *ptr) + { + __ASM volatile ("STLB %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT void __STLH(uint16_t value, volatile uint16_t *ptr) + { + __ASM volatile ("STLH %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT void __STL(uint32_t value, volatile uint32_t *ptr) + { + __ASM volatile ("STL %1, [%0]" :: "r" (ptr), "r" (value) : "memory"); + } + + __IAR_FT uint8_t __LDAEXB(volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEXB %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint8_t)res); + } + + __IAR_FT uint16_t __LDAEXH(volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEXH %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return ((uint16_t)res); + } + + __IAR_FT uint32_t __LDAEX(volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("LDAEX %0, [%1]" : "=r" (res) : "r" (ptr) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEXB %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEXH %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + + __IAR_FT uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) + { + uint32_t res; + __ASM volatile ("STLEX %0, %2, [%1]" : "=r" (res) : "r" (ptr), "r" (value) : "memory"); + return res; + } + +#endif /* __ARM_ARCH_8M_MAIN__ or __ARM_ARCH_8M_BASE__ */ + +#undef __IAR_FT +#undef __IAR_M0_FAMILY +#undef __ICCARM_V8 + +#pragma diag_default=Pe940 +#pragma diag_default=Pe177 + +#define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) + +#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) + +#endif /* __CMSIS_ICCARM_H__ */ diff --git a/lib/cmsis_core/cmsis_tiarmclang.h b/lib/cmsis_core/cmsis_tiarmclang.h new file mode 100644 index 000000000..4d799c277 --- /dev/null +++ b/lib/cmsis_core/cmsis_tiarmclang.h @@ -0,0 +1,1510 @@ +/**************************************************************************//** + * @file cmsis_tiarmclang.h + * @brief CMSIS compiler tiarmclang header file + * @version V1.0.0 + * @date 04. April 2023 + ******************************************************************************/ +/* + * Copyright (c) 2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*lint -esym(9058, IRQn)*/ /* disable MISRA 2012 Rule 2.4 for IRQn */ + +#ifndef __CMSIS_TIARMCLANG_H +#define __CMSIS_TIARMCLANG_H + +#pragma clang system_header /* treat file as system include file */ + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE __inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32 */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_WRITE */ + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT16_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT16_READ */ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_WRITE)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_WRITE */ + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wpacked" +/*lint -esym(9058, T_UINT32_READ)*/ /* disable MISRA 2012 Rule 2.4 for T_UINT32_READ */ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma clang diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif +#ifndef __COMPILER_BARRIER + #define __COMPILER_BARRIER() __ASM volatile("":::"memory") +#endif +#ifndef __NO_INIT + #define __NO_INIT __attribute__ ((section (".bss.noinit"))) +#endif +#ifndef __ALIAS + #define __ALIAS(x) __attribute__ ((alias(x))) +#endif + + +/* ######################### Startup and Lowlevel Init ######################## */ + +#ifndef __PROGRAM_START +#define __PROGRAM_START _c_int00 +#endif + +#ifndef __INITIAL_SP +#define __INITIAL_SP __STACK_END +#endif + +#ifndef __STACK_LIMIT +#define __STACK_LIMIT __STACK_SIZE +#endif + +#ifndef __VECTOR_TABLE +#define __VECTOR_TABLE __Vectors +#endif + +#ifndef __VECTOR_TABLE_ATTRIBUTE +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section(".intvecs"))) +#endif + +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#ifndef __STACK_SEAL +#define __STACK_SEAL Image$$STACKSEAL$$ZI$$Base +#endif + +#ifndef __TZ_STACK_SEAL_SIZE +#define __TZ_STACK_SEAL_SIZE 8U +#endif + +#ifndef __TZ_STACK_SEAL_VALUE +#define __TZ_STACK_SEAL_VALUE 0xFEF5EDA5FEF5EDA5ULL +#endif + + +__STATIC_FORCEINLINE void __TZ_set_STACKSEAL_S (uint32_t* stackTop) { + *((uint64_t *)stackTop) = __TZ_STACK_SEAL_VALUE; +} +#endif + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __builtin_arm_nop + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __builtin_arm_wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __builtin_arm_wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __builtin_arm_sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __builtin_arm_isb(0xF) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __builtin_arm_dsb(0xF) + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __builtin_arm_dmb(0xF) + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV(value) __builtin_bswap32(value) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV16(value) __ROR(__REV(value), 16) + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REVSH(value) (int16_t)__builtin_bswap16(value) + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __RBIT __builtin_arm_rbit + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) +{ + /* Even though __builtin_clz produces a CLZ instruction on ARM, formally + __builtin_clz(0) is undefined behaviour, so handle this case specially. + This guarantees ARM-compatible results if happening to compile on a non-ARM + target, and ensures the compiler doesn't decide to activate any + optimisations using the logic "value was passed to __builtin_clz, so it + is non-zero". + ARM Compiler 6.10 and possibly earlier will optimise this test away, leaving a + single CLZ instruction. + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +} + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDREXB (uint8_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDREXH (uint16_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDREXW (uint32_t)__builtin_arm_ldrex + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXB (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXH (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXW (uint32_t)__builtin_arm_strex + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __builtin_arm_clrex + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __builtin_arm_ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __builtin_arm_usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) : "memory" ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) : "memory" ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDAEXB (uint8_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDAEXH (uint16_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDAEX (uint32_t)__builtin_arm_ldaex + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXB (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXH (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEX (uint32_t)__builtin_arm_stlex + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** @}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} +#endif + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting special-purpose register PRIMASK. + Can only be executed in Privileged modes. + */ +#ifndef __ARM_COMPAT_H +__STATIC_FORCEINLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} +#endif + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); + __ISB(); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); + __ISB(); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting special-purpose register FAULTMASK. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__ ) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) ) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) || \ + (defined (__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ == 1)) ) */ + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __get_FPSCR (uint32_t)__builtin_arm_get_fpscr +#else +#define __get_FPSCR() ((uint32_t)0U) +#endif + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#define __set_FPSCR __builtin_arm_set_fpscr +#else +#define __set_FPSCR(fpscr) ((void)(fpscr)) +#endif + + +/** @} end of CMSIS_Core_RegAccFunctions */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +#define __SADD8 __builtin_arm_sadd8 +#define __QADD8 __builtin_arm_qadd8 +#define __SHADD8 __builtin_arm_shadd8 +#define __UADD8 __builtin_arm_uadd8 +#define __UQADD8 __builtin_arm_uqadd8 +#define __UHADD8 __builtin_arm_uhadd8 +#define __SSUB8 __builtin_arm_ssub8 +#define __QSUB8 __builtin_arm_qsub8 +#define __SHSUB8 __builtin_arm_shsub8 +#define __USUB8 __builtin_arm_usub8 +#define __UQSUB8 __builtin_arm_uqsub8 +#define __UHSUB8 __builtin_arm_uhsub8 +#define __SADD16 __builtin_arm_sadd16 +#define __QADD16 __builtin_arm_qadd16 +#define __SHADD16 __builtin_arm_shadd16 +#define __UADD16 __builtin_arm_uadd16 +#define __UQADD16 __builtin_arm_uqadd16 +#define __UHADD16 __builtin_arm_uhadd16 +#define __SSUB16 __builtin_arm_ssub16 +#define __QSUB16 __builtin_arm_qsub16 +#define __SHSUB16 __builtin_arm_shsub16 +#define __USUB16 __builtin_arm_usub16 +#define __UQSUB16 __builtin_arm_uqsub16 +#define __UHSUB16 __builtin_arm_uhsub16 +#define __SASX __builtin_arm_sasx +#define __QASX __builtin_arm_qasx +#define __SHASX __builtin_arm_shasx +#define __UASX __builtin_arm_uasx +#define __UQASX __builtin_arm_uqasx +#define __UHASX __builtin_arm_uhasx +#define __SSAX __builtin_arm_ssax +#define __QSAX __builtin_arm_qsax +#define __SHSAX __builtin_arm_shsax +#define __USAX __builtin_arm_usax +#define __UQSAX __builtin_arm_uqsax +#define __UHSAX __builtin_arm_uhsax +#define __USAD8 __builtin_arm_usad8 +#define __USADA8 __builtin_arm_usada8 +#define __SSAT16 __builtin_arm_ssat16 +#define __USAT16 __builtin_arm_usat16 +#define __UXTB16 __builtin_arm_uxtb16 +#define __UXTAB16 __builtin_arm_uxtab16 +#define __SXTB16 __builtin_arm_sxtb16 +#define __SXTAB16 __builtin_arm_sxtab16 +#define __SMUAD __builtin_arm_smuad +#define __SMUADX __builtin_arm_smuadx +#define __SMLAD __builtin_arm_smlad +#define __SMLADX __builtin_arm_smladx +#define __SMLALD __builtin_arm_smlald +#define __SMLALDX __builtin_arm_smlaldx +#define __SMUSD __builtin_arm_smusd +#define __SMUSDX __builtin_arm_smusdx +#define __SMLSD __builtin_arm_smlsd +#define __SMLSDX __builtin_arm_smlsdx +#define __SMLSLD __builtin_arm_smlsld +#define __SMLSLDX __builtin_arm_smlsldx +#define __SEL __builtin_arm_sel +#define __QADD __builtin_arm_qadd +#define __QSUB __builtin_arm_qsub + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SXTB16_RORn(ARG1, ARG2) __SXTB16(__ROR(ARG1, ARG2)) + +#define __SXTAB16_RORn(ARG1, ARG2, ARG3) __SXTAB16(ARG1, __ROR(ARG2, ARG3)) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/** @} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_TIARMCLANG_H */ diff --git a/lib/cmsis_core/cmsis_version.h b/lib/cmsis_core/cmsis_version.h new file mode 100644 index 000000000..8b4765f18 --- /dev/null +++ b/lib/cmsis_core/cmsis_version.h @@ -0,0 +1,39 @@ +/**************************************************************************//** + * @file cmsis_version.h + * @brief CMSIS Core(M) Version definitions + * @version V5.0.5 + * @date 02. February 2022 + ******************************************************************************/ +/* + * Copyright (c) 2009-2022 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CMSIS_VERSION_H +#define __CMSIS_VERSION_H + +/* CMSIS Version definitions */ +#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ +#define __CM_CMSIS_VERSION_SUB ( 6U) /*!< [15:0] CMSIS Core(M) sub version */ +#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ + __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ +#endif diff --git a/lib/cmsis_core/core_cm4.h b/lib/cmsis_core/core_cm4.h new file mode 100644 index 000000000..711c11326 --- /dev/null +++ b/lib/cmsis_core/core_cm4.h @@ -0,0 +1,2170 @@ +/**************************************************************************//** + * @file core_cm4.h + * @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File + * @version V5.2.0 + * @date 04. April 2023 + ******************************************************************************/ +/* + * Copyright (c) 2009-2023 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM4_H_GENERIC +#define __CORE_CM4_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M4 + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM4 definitions */ +#define __CM4_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM4_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM4_CMSIS_VERSION ((__CM4_CMSIS_VERSION_MAIN << 16U) | \ + __CM4_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (4U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined (__ti__) + #if defined (__ARM_FP) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM4_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM4_H_DEPENDANT +#define __CORE_CM4_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM4_REV + #define __CM4_REV 0x0000U + #warning "__CM4_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 1U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M4 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:1; /*!< bit: 9 Reserved */ + uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit */ + uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ +#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ +#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */ + uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RESERVED1[24U]; + __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[5U]; + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_MMARVALID_Pos (SCB_CFSR_MEMFAULTSR_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ +#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ + +#define SCB_CFSR_MLSPERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ +#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ + +#define SCB_CFSR_MSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ +#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ + +#define SCB_CFSR_MUNSTKERR_Pos (SCB_CFSR_MEMFAULTSR_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ +#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ + +#define SCB_CFSR_DACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ +#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ + +#define SCB_CFSR_IACCVIOL_Pos (SCB_CFSR_MEMFAULTSR_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ +#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ + +/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ +#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ + +#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ +#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ + +#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ +#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ + +#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ +#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ + +#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ +#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ + +#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ +#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ + +#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ +#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ + +/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ +#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ +#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ + +#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ +#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ + +#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ +#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ + +#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ +#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ + +#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ +#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ + +#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ +#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ +#define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ + +#define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ +#define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ + +#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ +#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ + +#define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ +#define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ + +#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ +#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[32U]; + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[6U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TRACEBUSID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TRACEBUSID_Msk (0x7FUL << ITM_TCR_TRACEBUSID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPRESCALE_Pos 8U /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPRESCALE_Msk (3UL << ITM_TCR_TSPRESCALE_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_BYTEACC_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_BYTEACC_Msk (1UL << ITM_LSR_BYTEACC_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_ACCESS_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_ACCESS_Msk (1UL << ITM_LSR_ACCESS_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_PRESENT_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_PRESENT_Msk (1UL /*<< ITM_LSR_PRESENT_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Mask Register Definitions */ +#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ +#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ +#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ + +#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ +#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ +#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ + +#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ +#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ + +#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ +#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ + +#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ +#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ + +#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ +#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ +#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ + +#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ +#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ +#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ + +#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ +#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +#define MPU_TYPE_RALIASES 4U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif /* defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x018 (R/ ) Media and FP Feature Register 2 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/* Media and FP Feature Register 2 Definitions */ + +#define FPU_MVFR2_VFP_Misc_Pos 4U /*!< MVFR2: VFP Misc bits Position */ +#define FPU_MVFR2_VFP_Misc_Msk (0xFUL << FPU_MVFR2_VFP_Misc_Pos) /*!< MVFR2: VFP Misc bits Mask */ + +/*@} end of group CMSIS_FPU */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ +#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ +#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ +#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +#define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ +#define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ + +/*@} */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_register_aliases Backwards Compatibility Aliases + \brief Register alias definitions for backwards compatibility. + @{ + */ + +/* Capitalize ITM_TCR Register Definitions */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_TraceBusID_Pos (ITM_TCR_TRACEBUSID_Pos) /*!< \deprecated ITM_TCR_TraceBusID_Pos */ +#define ITM_TCR_TraceBusID_Msk (ITM_TCR_TRACEBUSID_Msk) /*!< \deprecated ITM_TCR_TraceBusID_Msk */ + +#define ITM_TCR_TSPrescale_Pos (ITM_TCR_TSPRESCALE_Pos) /*!< \deprecated ITM_TCR_TSPrescale_Pos */ +#define ITM_TCR_TSPrescale_Msk (ITM_TCR_TSPRESCALE_Msk) /*!< \deprecated ITM_TCR_TSPrescale_Msk */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos (ITM_LSR_BYTEACC_Pos) /*!< \deprecated ITM_LSR_ByteAcc_Pos */ +#define ITM_LSR_ByteAcc_Msk (ITM_LSR_BYTEACC_Msk) /*!< \deprecated ITM_LSR_ByteAcc_Msk */ + +#define ITM_LSR_Access_Pos (ITM_LSR_ACCESS_Pos) /*!< \deprecated ITM_LSR_Access_Pos */ +#define ITM_LSR_Access_Msk (ITM_LSR_ACCESS_Msk) /*!< \deprecated ITM_LSR_Access_Msk */ + +#define ITM_LSR_Present_Pos (ITM_LSR_PRESENT_Pos) /*!< \deprecated ITM_LSR_Present_Pos */ +#define ITM_LSR_Present_Msk (ITM_LSR_PRESENT_Msk) /*!< \deprecated ITM_LSR_Present_Msk */ + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ + #define NVIC_GetActive __NVIC_GetActive + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ +#define EXC_RETURN_HANDLER_FPU (0xFFFFFFE1UL) /* return to Handler mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_MSP_FPU (0xFFFFFFE9UL) /* return to Thread mode, uses MSP after return, restore floating-point state */ +#define EXC_RETURN_THREAD_PSP_FPU (0xFFFFFFEDUL) /* return to Thread mode, uses PSP after return, restore floating-point state */ + + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + __COMPILER_BARRIER(); + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __COMPILER_BARRIER(); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; + /* ARM Application Note 321 states that the M4 does not require the architectural barrier */ +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = FPU->MVFR0; + if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) + { + return 1U; /* Single precision FPU */ + } + else + { + return 0U; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM4_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/lib/cmsis_core/mpu_armv7.h b/lib/cmsis_core/mpu_armv7.h new file mode 100644 index 000000000..d9eedf81a --- /dev/null +++ b/lib/cmsis_core/mpu_armv7.h @@ -0,0 +1,275 @@ +/****************************************************************************** + * @file mpu_armv7.h + * @brief CMSIS MPU API for Armv7-M MPU + * @version V5.1.2 + * @date 25. May 2020 + ******************************************************************************/ +/* + * Copyright (c) 2017-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef ARM_MPU_ARMV7_H +#define ARM_MPU_ARMV7_H + +#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes +#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes +#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes +#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes +#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes +#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte +#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes +#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes +#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes +#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes +#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes +#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes +#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes +#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes +#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes +#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte +#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes +#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes +#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes +#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes +#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes +#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes +#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes +#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes +#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes +#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte +#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes +#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes + +#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access +#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only +#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only +#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access +#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only +#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access + +/** MPU Region Base Address Register Value +* +* \param Region The region to be configured, number 0 to 15. +* \param BaseAddress The base address for the region. +*/ +#define ARM_MPU_RBAR(Region, BaseAddress) \ + (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ + ((Region) & MPU_RBAR_REGION_Msk) | \ + (MPU_RBAR_VALID_Msk)) + +/** +* MPU Memory Access Attributes +* +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +*/ +#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ + ((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ + (((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ + (((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ + (((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ + ((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ + (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ + (((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \ + (((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \ + (((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \ + (((MPU_RASR_ENABLE_Msk)))) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ + ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) + +/** +* MPU Memory Access Attribute for strongly ordered memory. +* - TEX: 000b +* - Shareable +* - Non-cacheable +* - Non-bufferable +*/ +#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) + +/** +* MPU Memory Access Attribute for device memory. +* - TEX: 000b (if shareable) or 010b (if non-shareable) +* - Shareable or non-shareable +* - Non-cacheable +* - Bufferable (if shareable) or non-bufferable (if non-shareable) +* +* \param IsShareable Configures the device memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) + +/** +* MPU Memory Access Attribute for normal memory. +* - TEX: 1BBb (reflecting outer cacheability rules) +* - Shareable or non-shareable +* - Cacheable or non-cacheable (reflecting inner cacheability rules) +* - Bufferable or non-bufferable (reflecting inner cacheability rules) +* +* \param OuterCp Configures the outer cache policy. +* \param InnerCp Configures the inner cache policy. +* \param IsShareable Configures the memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U)) + +/** +* MPU Memory Access Attribute non-cacheable policy. +*/ +#define ARM_MPU_CACHEP_NOCACHE 0U + +/** +* MPU Memory Access Attribute write-back, write and read allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_WRA 1U + +/** +* MPU Memory Access Attribute write-through, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WT_NWA 2U + +/** +* MPU Memory Access Attribute write-back, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_NWA 3U + + +/** +* Struct for a single MPU Region +*/ +typedef struct { + uint32_t RBAR; //!< The region base address register value (RBAR) + uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR +} ARM_MPU_Region_t; + +/** Enable the MPU. +* \param MPU_Control Default access permissions for unconfigured regions. +*/ +__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) +{ + __DMB(); + MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; +#endif + __DSB(); + __ISB(); +} + +/** Disable the MPU. +*/ +__STATIC_INLINE void ARM_MPU_Disable(void) +{ + __DMB(); +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; +#endif + MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; + __DSB(); + __ISB(); +} + +/** Clear and disable the given MPU region. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) +{ + MPU->RNR = rnr; + MPU->RASR = 0U; +} + +/** Configure an MPU region. +* \param rbar Value for RBAR register. +* \param rasr Value for RASR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) +{ + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Configure the given MPU region. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rasr Value for RASR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) +{ + MPU->RNR = rnr; + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load(). +* \param dst Destination data is copied to. +* \param src Source data is copied from. +* \param len Amount of data words to be copied. +*/ +__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) +{ + uint32_t i; + for (i = 0U; i < len; ++i) + { + dst[i] = src[i]; + } +} + +/** Load the given number of MPU regions from a table. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) +{ + const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; + while (cnt > MPU_TYPE_RALIASES) { + ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); + table += MPU_TYPE_RALIASES; + cnt -= MPU_TYPE_RALIASES; + } + ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); +} + +#endif diff --git a/lib/stm32wb.scons b/lib/stm32wb.scons new file mode 100644 index 000000000..9c184872b --- /dev/null +++ b/lib/stm32wb.scons @@ -0,0 +1,70 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/cmsis_core", + "#/lib/stm32wb_cmsis/Include", + "#/lib/stm32wb_hal/Inc", + "#/lib/stm32wb_copro/wpan", + ], + CPPDEFINES=[ + "STM32WB", + "STM32WB55xx", + "USE_FULL_ASSERT", + "USE_FULL_LL_DRIVER", + ], + SDK_HEADERS=env.GlobRecursive( + "*_ll_*.h", + Dir("stm32wb_hal/Inc"), + exclude="*usb.h", + ), +) + +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "VECT_TAB_SRAM", + ], + ) + + +libenv = env.Clone(FW_LIB_NAME="stm32wb") +libenv.Append( + CPPPATH=[ + "#/lib/stm32wb_copro/wpan/ble", + "#/lib/stm32wb_copro/wpan/ble/core", + "#/lib/stm32wb_copro/wpan/interface/patterns/ble_thread", + "#/lib/stm32wb_copro/wpan/interface/patterns/ble_thread/shci", + "#/lib/stm32wb_copro/wpan/interface/patterns/ble_thread/tl", + "#/lib/stm32wb_copro/wpan/utilities", + ] +) +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*_ll_*.c", "stm32wb_hal/Src/", exclude="*usb.c") +sources += Glob( + "stm32wb_copro/wpan/interface/patterns/ble_thread/shci/*.c", + source=True, +) +sources += Glob( + "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/*_tl*.c", + source=True, +) +sources += [ + "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/tl_mbox.c", + "stm32wb_copro/wpan/ble/svc/Src/svc_ctl.c", + "stm32wb_copro/wpan/ble/core/auto/ble_gap_aci.c", + "stm32wb_copro/wpan/ble/core/auto/ble_gatt_aci.c", + "stm32wb_copro/wpan/ble/core/auto/ble_hal_aci.c", + "stm32wb_copro/wpan/ble/core/auto/ble_hci_le.c", + "stm32wb_copro/wpan/ble/core/auto/ble_l2cap_aci.c", + "stm32wb_copro/wpan/ble/core/template/osal.c", + "stm32wb_copro/wpan/utilities/dbg_trace.c", + "stm32wb_copro/wpan/utilities/otp.c", + "stm32wb_copro/wpan/utilities/stm_list.c", +] + + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/stm32wb_cmsis b/lib/stm32wb_cmsis new file mode 160000 index 000000000..d1b860584 --- /dev/null +++ b/lib/stm32wb_cmsis @@ -0,0 +1 @@ +Subproject commit d1b860584dfe24d40d455ae624ed14600dfa93c9 diff --git a/lib/stm32wb_copro b/lib/stm32wb_copro new file mode 160000 index 000000000..6c9c54f05 --- /dev/null +++ b/lib/stm32wb_copro @@ -0,0 +1 @@ +Subproject commit 6c9c54f05669b2c4d436df58bb691d3b0d7c86df diff --git a/lib/stm32wb_hal b/lib/stm32wb_hal new file mode 160000 index 000000000..cfd0dd258 --- /dev/null +++ b/lib/stm32wb_hal @@ -0,0 +1 @@ +Subproject commit cfd0dd258cb031c95b2b2d6d04c19f9f625fe3e8 diff --git a/scripts/assets.py b/scripts/assets.py index c0fa9100b..bd8b38ae6 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -60,7 +60,6 @@ class Main(App): ) self.parser_copro.add_argument("cube_dir", help="Path to Cube folder") self.parser_copro.add_argument("output_dir", help="Path to output folder") - self.parser_copro.add_argument("mcu", help="MCU series as in copro folder") self.parser_copro.add_argument( "--cube_ver", dest="cube_ver", help="Cube version", required=True ) @@ -254,16 +253,20 @@ class Main(App): from flipper.assets.copro import Copro self.logger.info("Bundling coprocessor binaries") - copro = Copro(self.args.mcu) - self.logger.info("Loading CUBE info") - copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver) - self.logger.info("Bundling") - copro.bundle( - self.args.output_dir, - self.args.stack_file, - self.args.stack_type, - self.args.stack_addr, - ) + copro = Copro() + try: + self.logger.info("Loading CUBE info") + copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver) + self.logger.info("Bundling") + copro.bundle( + self.args.output_dir, + self.args.stack_file, + self.args.stack_type, + self.args.stack_addr, + ) + except Exception as e: + self.logger.error(f"Failed to bundle: {e}") + return 1 self.logger.info("Complete") return 0 diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index ee13a9b5e..f176e3b2e 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -1,16 +1,14 @@ -import logging import json -from io import BytesIO -import tarfile -import xml.etree.ElementTree as ET -import posixpath +import logging import os +import posixpath +import tarfile +from io import BytesIO -from flipper.utils import file_sha256, timestamp from flipper.assets.coprobin import CoproBinary, get_stack_type +from flipper.utils import file_sha256, timestamp - -CUBE_COPRO_PATH = "Projects/STM32WB_Copro_Wireless_Binaries" +CUBE_COPRO_PATH = "firmware" MANIFEST_TEMPLATE = { "manifest": {"version": 0, "timestamp": 0}, @@ -27,8 +25,7 @@ MANIFEST_TEMPLATE = { class Copro: COPRO_TAR_DIR = "core2_firmware" - def __init__(self, mcu): - self.mcu = mcu + def __init__(self): self.version = None self.cube_dir = None self.mcu_copro = None @@ -38,20 +35,24 @@ class Copro: if not os.path.isdir(cube_dir): raise Exception(f'"{cube_dir}" doesn\'t exists') self.cube_dir = cube_dir - self.mcu_copro = os.path.join(self.cube_dir, CUBE_COPRO_PATH, self.mcu) + self.mcu_copro = os.path.join(self.cube_dir, CUBE_COPRO_PATH) if not os.path.isdir(self.mcu_copro): raise Exception(f'"{self.mcu_copro}" doesn\'t exists') - cube_manifest_file = os.path.join(self.cube_dir, "package.xml") - cube_manifest = ET.parse(cube_manifest_file) - cube_package = cube_manifest.find("PackDescription") - if not cube_package: - raise Exception("Unknown Cube manifest format") - cube_version = cube_package.get("Patch") or cube_package.get("Release") - if not cube_version or not cube_version.startswith("FW.WB"): - raise Exception("Incorrect Cube package or version info") - cube_version = cube_version.replace("FW.WB.", "", 1) + try: + cube_manifest_file = os.path.join(self.cube_dir, "VERSION") + with open(cube_manifest_file, "r") as cube_manifest: + cube_version = cube_manifest.read().strip() + except IOError: + raise Exception(f"Failed to read version from {cube_manifest_file}") + + if not cube_version.startswith("v"): + raise Exception(f"Invalid cube version: {cube_version}") + cube_version = cube_version[1:] + if cube_version != reference_cube_version: - raise Exception("Unsupported cube version") + raise Exception( + f"Unsupported cube version: {cube_version}, expecting {reference_cube_version}" + ) self.version = cube_version def _getFileName(self, name): diff --git a/scripts/flipper/assets/coprobin.py b/scripts/flipper/assets/coprobin.py index 7c5bdb3dc..75bf76d76 100644 --- a/scripts/flipper/assets/coprobin.py +++ b/scripts/flipper/assets/coprobin.py @@ -5,7 +5,7 @@ import os.path import sys -# From STM32CubeWB\Middlewares\ST\STM32_WPAN\interface\patterns\ble_thread\shci\shci.h +# From lib/stm32wb_copro/wpan/interface/patterns/ble_thread/shci/shci.h __STACK_TYPE_CODES = { "BLE_FULL": 0x01, "BLE_HCI": 0x02, From 241b4ef6e4096005290aedd1bc35e56398c579dd Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 9 May 2023 01:31:39 +0300 Subject: [PATCH 153/216] [FL-3299] furi_crash: added C2 status; added fw-version gdb command (#2638) * furi_crash: added C2 status * debug: Added "fw-version" gdb command; vscode: updated configuration to use new command * debug: added fw-info command to debug_other session * Toolbox: versioned structure for Version * debug: fw-version: no longer needs an ELF file loaded * debug: flipperversion: removed unused variable * debug_other: print running fw version Co-authored-by: Aleksandr Kutuzov --- .vscode/example/launch.json | 17 ++- SConstruct | 16 ++- debug/flipperversion.py | 109 ++++++++++++++++++ firmware/targets/f18/api_symbols.csv | 3 +- firmware/targets/f7/api_symbols.csv | 3 +- firmware/targets/f7/furi_hal/furi_hal_bt.c | 11 ++ .../targets/furi_hal_include/furi_hal_bt.h | 13 +++ furi/core/check.c | 16 +++ lib/toolbox/version.c | 20 +++- scripts/fbt_tools/fbt_debugopts.py | 8 +- .../ufbt/project_template/.vscode/launch.json | 8 ++ scripts/version.py | 3 - 12 files changed, 205 insertions(+), 22 deletions(-) create mode 100644 debug/flipperversion.py diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index 4cab026fa..b0bb9e245 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -36,6 +36,8 @@ "./debug/stm32wbx.cfg", ], "postAttachCommands": [ + "source debug/flipperversion.py", + "fw-version", // "compare-sections", "source debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", @@ -59,6 +61,8 @@ "attach 1", "set confirm off", "set mem inaccessible-by-default off", + "source debug/flipperversion.py", + "fw-version", "source debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", // "compare-sections", @@ -77,6 +81,8 @@ "svdFile": "./debug/STM32WB55_CM4.svd", "rtos": "FreeRTOS", "postAttachCommands": [ + "source debug/flipperversion.py", + "fw-version", "source debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", ] @@ -97,20 +103,13 @@ "./debug/stm32wbx.cfg", ], "postAttachCommands": [ + "source debug/flipperversion.py", + "fw-version", "source debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", ], // "showDevDebugOutput": "raw", }, - { - "name": "fbt debug", - "type": "python", - "request": "launch", - "program": "./lib/scons/scripts/scons.py", - "args": [ - "plugin_dist" - ] - }, { "name": "python debug", "type": "python", diff --git a/SConstruct b/SConstruct index 12f1166eb..e2568287d 100644 --- a/SConstruct +++ b/SConstruct @@ -239,19 +239,31 @@ distenv.PhonyTarget( ) # Debug alien elf +debug_other_opts = [ + "-ex", + "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py", + # "-ex", + # "source ${FBT_DEBUG_DIR}/FreeRTOS/FreeRTOS.py", + "-ex", + "source ${FBT_DEBUG_DIR}/flipperversion.py", + "-ex", + "fw-version", +] + distenv.PhonyTarget( "debug_other", "${GDBPYCOM}", GDBOPTS="${GDBOPTS_BASE}", GDBREMOTE="${OPENOCD_GDB_PIPE}", - GDBPYOPTS='-ex "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py" ', + GDBPYOPTS=debug_other_opts, ) distenv.PhonyTarget( "debug_other_blackmagic", "${GDBPYCOM}", GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", - GDBREMOTE="$${BLACKMAGIC_ADDR}", + GDBREMOTE="${BLACKMAGIC_ADDR}", + GDBPYOPTS=debug_other_opts, ) diff --git a/debug/flipperversion.py b/debug/flipperversion.py new file mode 100644 index 000000000..4ac3bd200 --- /dev/null +++ b/debug/flipperversion.py @@ -0,0 +1,109 @@ +from dataclasses import dataclass, field +from typing import Dict, Optional + +import gdb + + +# Must match FuriHalRtcRegisterVersion index in FuriHalRtcRegister enum +RTC_BACKUP_VERSION_REGISTER_IDX = 0x2 + +RTC_BASE = 0x40002800 +RTC_BACKUP_BASE = RTC_BASE + 0x50 + +VERSION_REGISTER_ADDRESS = RTC_BACKUP_BASE + RTC_BACKUP_VERSION_REGISTER_IDX * 4 + +VERSION_STRUCT_MAGIC = 0xBE40 + + +@dataclass +class VersionData: + git_hash: str + git_branch: str + build_date: str + version: str + target: int + build_is_dirty: bool + extra: Optional[Dict[str, str]] = field(default_factory=dict) + + +class VersionLoader: + def __init__(self, version_ptr): + self.version_ptr = version_ptr + self._cstr_type = gdb.lookup_type("char").pointer() + self._uint_type = gdb.lookup_type("unsigned int") + + version_signature = version_ptr.dereference().cast(self._uint_type) + is_versioned = (version_signature & (0xFFFF)) == VERSION_STRUCT_MAGIC + if is_versioned: + self._version_data = self.load_versioned( + major=version_signature >> 16 & 0xFF, + minor=version_signature >> 24 & 0xFF, + ) + else: + self._version_data = self.load_unversioned() + + @property + def version(self) -> VersionData: + return self._version_data + + def load_versioned(self, major, minor): + if major != 1: + raise ValueError("Unsupported version struct major version") + + # Struct version 1.0 + extra_data = int(self.version_ptr[5].cast(self._uint_type)) + return VersionData( + git_hash=self.version_ptr[1].cast(self._cstr_type).string(), + git_branch=self.version_ptr[2].cast(self._cstr_type).string(), + build_date=self.version_ptr[3].cast(self._cstr_type).string(), + version=self.version_ptr[4].cast(self._cstr_type).string(), + target=extra_data & 0xF, + build_is_dirty=bool((extra_data >> 8) & 0xF), + ) + + def load_unversioned(self): + """Parse an early version of the version struct.""" + extra_data = int(self.version_ptr[5].cast(self._uint_type)) + return VersionData( + git_hash=self.version_ptr[0].cast(self._cstr_type).string(), + git_branch=self.version_ptr[1].cast(self._cstr_type).string(), + # branch number is #2, but we don't care about it + build_date=self.version_ptr[3].cast(self._cstr_type).string(), + version=self.version_ptr[4].cast(self._cstr_type).string(), + target=extra_data & 0xF, + build_is_dirty=bool((extra_data >> 8) & 0xF), + ) + + +class FlipperFwVersion(gdb.Command): + """Print the version of Flipper's firmware.""" + + def __init__(self): + super(FlipperFwVersion, self).__init__("fw-version", gdb.COMMAND_USER) + + def invoke(self, arg, from_tty): + void_ptr_type = gdb.lookup_type("void").pointer().pointer() + version_ptr_ptr = gdb.Value(VERSION_REGISTER_ADDRESS).cast(void_ptr_type) + + if not version_ptr_ptr: + print("RTC version register is NULL") + return + + version_ptr = version_ptr_ptr.dereference() + if not version_ptr: + print("Pointer to version struct is NULL") + return + + version_struct = version_ptr.cast(void_ptr_type) + + v = VersionLoader(version_struct) + print("Firmware version on attached Flipper:") + print(f"\tVersion: {v.version.version}") + print(f"\tBuilt on: {v.version.build_date}") + print(f"\tGit branch: {v.version.git_branch}") + print(f"\tGit commit: {v.version.git_hash}") + print(f"\tDirty: {v.version.build_is_dirty}") + print(f"\tHW Target: {v.version.target}") + + +FlipperFwVersion() diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 8db084e2f..7a892e1cc 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,+,26.0,, +Version,+,26.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -823,6 +823,7 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi Function,+,furi_hal_bt_clear_white_list,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*, Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 643835608..6cb421a1b 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,26.0,, +Version,+,26.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1004,6 +1004,7 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi Function,+,furi_hal_bt_clear_white_list,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*, Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index b08c9ea27..048a8b309 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -19,6 +19,8 @@ /* Time, in ms, to wait for mode transition before crashing */ #define C2_MODE_SWITCH_TIMEOUT 10000 +#define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F + FuriMutex* furi_hal_bt_core2_mtx = NULL; static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown; @@ -440,3 +442,12 @@ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) { FURI_LOG_E(TAG, "Failed to switch C2 mode: %d", fw_start_res); return false; } + +const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info() { + /* AN5289, 4.8.2 */ + const FuriHalBtHardfaultInfo* info = (FuriHalBtHardfaultInfo*)(SRAM2A_BASE); + if(info->magic != FURI_HAL_BT_HARDFAULT_INFO_MAGIC) { + return NULL; + } + return info; +} diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index 196b2edb3..6ba38cb5e 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -224,6 +224,19 @@ uint32_t furi_hal_bt_get_transmitted_packets(); */ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode); +typedef struct { + uint32_t magic; + uint32_t source_pc; + uint32_t source_lr; + uint32_t source_sp; +} FuriHalBtHardfaultInfo; + +/** Get hardfault info + * + * @return hardfault info. NULL if no hardfault + */ +const FuriHalBtHardfaultInfo* furi_hal_bt_get_hardfault_info(); + #ifdef __cplusplus } #endif diff --git a/furi/core/check.c b/furi/core/check.c index f5390639d..478f3aacc 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,20 @@ static void __furi_print_stack_info() { __furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4); } +static void __furi_print_bt_stack_info() { + const FuriHalBtHardfaultInfo* fault_info = furi_hal_bt_get_hardfault_info(); + if(fault_info == NULL) { + furi_hal_console_puts("\r\n\tcore2: not faulted"); + } else { + furi_hal_console_puts("\r\n\tcore2: hardfaulted.\r\n\tPC: "); + __furi_put_uint32_as_hex(fault_info->source_pc); + furi_hal_console_puts("\r\n\tLR: "); + __furi_put_uint32_as_hex(fault_info->source_lr); + furi_hal_console_puts("\r\n\tSP: "); + __furi_put_uint32_as_hex(fault_info->source_sp); + } +} + static void __furi_print_heap_info() { furi_hal_console_puts("\r\n\t heap total: "); __furi_put_uint32_as_text(xPortGetTotalHeapSize()); @@ -136,6 +151,7 @@ FURI_NORETURN void __furi_crash() { __furi_print_stack_info(); } __furi_print_heap_info(); + __furi_print_bt_stack_info(); #ifndef FURI_DEBUG // Check if debug enabled by DAP diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index c6c10b410..6ba68e364 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -1,23 +1,34 @@ #include "version.h" - +#include /* This header is autogenerated by build system */ #include "version.inc.h" +#define VERSION_MAGIC (0xBE40u) +#define VERSION_MAJOR (0x1u) +#define VERSION_MINOR (0x0u) + struct Version { + // Header + const uint16_t magic; + const uint8_t major; + const uint8_t minor; + // Payload const char* git_hash; const char* git_branch; - const char* git_branch_num; const char* build_date; const char* version; + // Payload bits and pieces const uint8_t target; const bool build_is_dirty; }; /* version of current running firmware (bootloader/flipper) */ static const Version version = { + .magic = VERSION_MAGIC, + .major = VERSION_MAJOR, + .minor = VERSION_MINOR, .git_hash = GIT_COMMIT, .git_branch = GIT_BRANCH, - .git_branch_num = GIT_BRANCH_NUM, .build_date = BUILD_DATE, .version = VERSION #ifdef FURI_RAM_EXEC @@ -41,7 +52,8 @@ const char* version_get_gitbranch(const Version* v) { } const char* version_get_gitbranchnum(const Version* v) { - return v ? v->git_branch_num : version.git_branch_num; + UNUSED(v); + return "0"; } const char* version_get_builddate(const Version* v) { diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index 33cc0c076..58e73e9c9 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -39,10 +39,10 @@ def generate(env, **kw): "|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}" ], GDBOPTS_BASE=[ - "-ex", - "target extended-remote ${GDBREMOTE}", "-ex", "source ${FBT_DEBUG_DIR}/gdbinit", + "-ex", + "target extended-remote ${GDBREMOTE}", ], GDBOPTS_BLACKMAGIC=[ "-q", @@ -61,6 +61,8 @@ def generate(env, **kw): "-ex", "source ${FBT_DEBUG_DIR}/flipperapps.py", "-ex", + "source ${FBT_DEBUG_DIR}/flipperversion.py", + "-ex", "fap-set-debug-elf-root ${FBT_FAP_DEBUG_ELF_ROOT}", "-ex", "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py", @@ -68,6 +70,8 @@ def generate(env, **kw): "svd_load ${SVD_FILE}", "-ex", "compare-sections", + "-ex", + "fw-version", ], JFLASHPROJECT="${FBT_DEBUG_DIR}/fw.jflash", ) diff --git a/scripts/ufbt/project_template/.vscode/launch.json b/scripts/ufbt/project_template/.vscode/launch.json index 697de9a49..3269bab57 100644 --- a/scripts/ufbt/project_template/.vscode/launch.json +++ b/scripts/ufbt/project_template/.vscode/launch.json @@ -29,6 +29,8 @@ "@UFBT_DEBUG_DIR@/stm32wbx.cfg" ], "postAttachCommands": [ + "source @UFBT_DEBUG_DIR@/flipperversion.py", + "fw-version", "source @UFBT_DEBUG_DIR@/flipperapps.py", "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" ], @@ -49,6 +51,8 @@ "@UFBT_DEBUG_DIR@/stm32wbx.cfg" ], "postAttachCommands": [ + "source @UFBT_DEBUG_DIR@/flipperversion.py", + "fw-version", "source @UFBT_DEBUG_DIR@/flipperapps.py", "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" ], @@ -69,6 +73,8 @@ "attach 1", "set confirm off", "set mem inaccessible-by-default off", + "source @UFBT_DEBUG_DIR@/flipperversion.py", + "fw-version", "source @UFBT_DEBUG_DIR@/flipperapps.py", "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" ] @@ -86,6 +92,8 @@ "svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd", "rtos": "FreeRTOS", "postAttachCommands": [ + "source @UFBT_DEBUG_DIR@/flipperversion.py", + "fw-version", "source @UFBT_DEBUG_DIR@/flipperapps.py", "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" ] diff --git a/scripts/version.py b/scripts/version.py index 71d201abb..3d68b2e98 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -35,8 +35,6 @@ class GitVersion: or "unknown" ) - branch_num = self._exec_git("rev-list --count HEAD") or "n/a" - try: version = self._exec_git("describe --tags --abbrev=0 --exact-match") except subprocess.CalledProcessError: @@ -45,7 +43,6 @@ class GitVersion: return { "GIT_COMMIT": commit, "GIT_BRANCH": branch, - "GIT_BRANCH_NUM": branch_num, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, } From f57f0efc4837f2c33e881f58477bb0f27884576b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 9 May 2023 08:31:44 +0900 Subject: [PATCH 154/216] Debug: revert cortex debug to lxml and drop DWT (#2651) * Debug: revert cortex debug to lxml * Debug: update PyCortexMDebug readme * fbt: moved "debug" dir to "scripts" subfolder * ufbt: added missing debug_other & debug_other_blackmagic targets; github: fixed script bundling * lint: fixed formatting on debug scripts * vscode: updated configuration for debug dir changes --------- Co-authored-by: hedger Co-authored-by: hedger --- .github/workflows/build.yml | 2 +- .vscode/example/launch.json | 31 +- debug/PyCortexMDebug/README.md | 84 --- debug/PyCortexMDebug/cmdebug/dwt_gdb.py | 160 ----- debug/PyCortexMDebug/cmdebug/x2d.py | 586 ------------------ {debug => scripts/debug}/FreeRTOS/FreeRTOS.py | 1 - .../debug}/FreeRTOS/FreeRTOSgdb/EventGroup.py | 0 .../FreeRTOS/FreeRTOSgdb/GDBCommands.py | 1 - .../FreeRTOS/FreeRTOSgdb/HandleRegistry.py | 1 - .../debug}/FreeRTOS/FreeRTOSgdb/List.py | 2 - .../debug}/FreeRTOS/FreeRTOSgdb/QueueTools.py | 1 - .../debug}/FreeRTOS/FreeRTOSgdb/Task.py | 1 - .../debug}/FreeRTOS/FreeRTOSgdb/Types.py | 0 .../debug}/FreeRTOS/FreeRTOSgdb/__init__.py | 0 {debug => scripts/debug}/FreeRTOS/LICENSE | 0 {debug => scripts/debug}/FreeRTOS/README.md | 0 .../debug}/PyCortexMDebug/LICENSE | 0 .../debug}/PyCortexMDebug/PyCortexMDebug.py | 2 - scripts/debug/PyCortexMDebug/README.md | 35 ++ .../debug}/PyCortexMDebug/cmdebug/__init__.py | 0 .../debug}/PyCortexMDebug/cmdebug/svd.py | 70 +-- .../debug}/PyCortexMDebug/cmdebug/svd_gdb.py | 0 {debug => scripts/debug}/STM32WB55_CM4.svd | 0 {debug => scripts/debug}/flipperapps.py | 0 {debug => scripts/debug}/flipperversion.py | 0 {debug => scripts/debug}/fw.jflash | 0 {debug => scripts/debug}/gdbinit | 0 {debug => scripts/debug}/stm32wbx.cfg | 0 scripts/fbt_tools/fbt_debugopts.py | 2 +- scripts/sconsdist.py | 1 - scripts/ufbt/SConstruct | 27 + scripts/ufbt/site_tools/ufbt_state.py | 4 +- 32 files changed, 113 insertions(+), 898 deletions(-) delete mode 100644 debug/PyCortexMDebug/README.md delete mode 100755 debug/PyCortexMDebug/cmdebug/dwt_gdb.py delete mode 100644 debug/PyCortexMDebug/cmdebug/x2d.py rename {debug => scripts/debug}/FreeRTOS/FreeRTOS.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/EventGroup.py (100%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/GDBCommands.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/HandleRegistry.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/List.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/QueueTools.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/Task.py (99%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/Types.py (100%) rename {debug => scripts/debug}/FreeRTOS/FreeRTOSgdb/__init__.py (100%) rename {debug => scripts/debug}/FreeRTOS/LICENSE (100%) rename {debug => scripts/debug}/FreeRTOS/README.md (100%) rename {debug => scripts/debug}/PyCortexMDebug/LICENSE (100%) rename {debug => scripts/debug}/PyCortexMDebug/PyCortexMDebug.py (96%) create mode 100644 scripts/debug/PyCortexMDebug/README.md rename {debug => scripts/debug}/PyCortexMDebug/cmdebug/__init__.py (100%) rename {debug => scripts/debug}/PyCortexMDebug/cmdebug/svd.py (89%) rename {debug => scripts/debug}/PyCortexMDebug/cmdebug/svd_gdb.py (100%) rename {debug => scripts/debug}/STM32WB55_CM4.svd (100%) rename {debug => scripts/debug}/flipperapps.py (100%) rename {debug => scripts/debug}/flipperversion.py (100%) rename {debug => scripts/debug}/fw.jflash (100%) rename {debug => scripts/debug}/gdbinit (100%) rename {debug => scripts/debug}/stm32wbx.cfg (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d69318530..8358d1706 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,7 +60,7 @@ jobs: - name: 'Bundle scripts' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts debug + tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts - name: 'Build the firmware' run: | diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index b0bb9e245..f4b7c6e48 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -27,22 +27,21 @@ "type": "cortex-debug", "servertype": "openocd", "device": "stlink", - "svdFile": "./debug/STM32WB55_CM4.svd", + "svdFile": "./scripts/debug/STM32WB55_CM4.svd", // If you're debugging early in the boot process, before OS scheduler is running, // you have to comment out the following line. "rtos": "FreeRTOS", "configFiles": [ "interface/stlink.cfg", - "./debug/stm32wbx.cfg", + "./scripts/debug/stm32wbx.cfg", ], "postAttachCommands": [ - "source debug/flipperversion.py", + "source scripts/debug/flipperversion.py", "fw-version", // "compare-sections", - "source debug/flipperapps.py", + "source scripts/debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", - // "source debug/FreeRTOS/FreeRTOS.py", - // "svd_load debug/STM32WB55_CM4.svd" + // "source scripts/debug/FreeRTOS/FreeRTOS.py", ] // "showDevDebugOutput": "raw", }, @@ -54,16 +53,16 @@ "type": "cortex-debug", "servertype": "external", "gdbTarget": "${input:BLACKMAGIC}", - "svdFile": "./debug/STM32WB55_CM4.svd", + "svdFile": "./scripts/debug/STM32WB55_CM4.svd", "rtos": "FreeRTOS", "postAttachCommands": [ "monitor swdp_scan", "attach 1", "set confirm off", "set mem inaccessible-by-default off", - "source debug/flipperversion.py", + "source scripts/debug/flipperversion.py", "fw-version", - "source debug/flipperapps.py", + "source scripts/debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", // "compare-sections", ] @@ -78,12 +77,12 @@ "servertype": "jlink", "interface": "swd", "device": "STM32WB55RG", - "svdFile": "./debug/STM32WB55_CM4.svd", + "svdFile": "./scripts/debug/STM32WB55_CM4.svd", "rtos": "FreeRTOS", "postAttachCommands": [ - "source debug/flipperversion.py", + "source scripts/debug/flipperversion.py", "fw-version", - "source debug/flipperapps.py", + "source scripts/debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", ] // "showDevDebugOutput": "raw", @@ -96,16 +95,16 @@ "type": "cortex-debug", "servertype": "openocd", "device": "cmsis-dap", - "svdFile": "./debug/STM32WB55_CM4.svd", + "svdFile": "./scripts/debug/STM32WB55_CM4.svd", "rtos": "FreeRTOS", "configFiles": [ "interface/cmsis-dap.cfg", - "./debug/stm32wbx.cfg", + "./scripts/debug/stm32wbx.cfg", ], "postAttachCommands": [ - "source debug/flipperversion.py", + "source scripts/debug/flipperversion.py", "fw-version", - "source debug/flipperapps.py", + "source scripts/debug/flipperapps.py", "fap-set-debug-elf-root build/latest/.extapps", ], // "showDevDebugOutput": "raw", diff --git a/debug/PyCortexMDebug/README.md b/debug/PyCortexMDebug/README.md deleted file mode 100644 index 32c76e765..000000000 --- a/debug/PyCortexMDebug/README.md +++ /dev/null @@ -1,84 +0,0 @@ -PyCortexMDebug -============== - -*A set of GDB/Python-based utilities to make life debugging ARM Cortex-M processors a bit easier* - -It will consist of several modules which will hopefully become integrated as they evolve. Presently, there is only one: - -## SVD -ARM defines an SVD (System View Description) file format in its CMSIS -standard as a means for Cortex-M-based chip manufacturers to provide a -common description of peripherals, registers, and register fields. You -can download SVD files for different manufacturers -[here](http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php). - -My implementation so far has only tested STM32 chips but should hold for others. If others are like those from ST, -expect plenty of errors in the file. Like GPIOA having a register named GPIOB_OSPEEDR and lots of 16-bit registers -that are listed as 32! - -The implementation consists of two components -- An xml parser module (pysvd) and a GDB file (gdb_svd). -I haven't yet worked out a perfect workflow for this, though it's quite easy to use when -you already tend to have a GDB initialization file for starting up OpenOCD and the like. -However your workflow works, just make sure to, in GDB: - - source gdb_svd.py - svd_load [your_svd_file].svd - -These files can be huge so it might take a second or two. Anyways, after that, you can do - - svd - -to list available peripherals with descriptions. Or you can do - - svd [some_peripheral_name] - -to see all of the registers (with their values) for a given peripheral. For more details, run - - svd [some_peripheral_name] [some_register_name] - -to see all of the field values with descriptions. - -You can add format modifiers like: - -* `svd/x` will display values in hex -* `svd/o` will display values in octal -* `svd/t` or `svd/b` will display values in binary -* `svd/a` will display values in hex and try to resolve symbols from the values - -All field values are displayed at the correct lengths as provided by the SVD files. -Also, tab completion exists for nearly everything! When in doubt, run `svd help`. - -### TODO - -Enable writing to registers and individual fields - -### Bugs - -There are probably a few. All planning, writing, and testing of this was done in an afternoon. There may be -some oddities in working with non-STM32 parts. I'll play with this when I start working with other -controllers again. If something's giving you trouble, describe the problem and it shall be fixed. - -## DWT -The ARM Data Watchpoint and Trace Unit (DWT) offers data watchpoints and a series of gated cycle counters. For now, -I only support the raw cycle counter but facilities are in place to make use of others. As this is independent of the -specific device under test, commands are simple and you can configure a clock speed to get real time values from -counters. - - dwt configclk 48000000 - -will set the current core clock speed. Then - - dwt cyccnt reset - dwt cyccnt enable - -will reset and start the cycle counter. At any point - - dwt cycnt - -will then indicate the number of cycles and amount of time that has passed. - -## ITM/ETM support - -This is not implemented yet. I want to have more complete support for some of the nicer debug and trace features -on Cortex-M processors. Parts of this will probably be dependent on OpenOCD and possibly on specific interfaces. -I'll try to avoid this where possible but can't make any promises. diff --git a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py b/debug/PyCortexMDebug/cmdebug/dwt_gdb.py deleted file mode 100755 index dd7ccd207..000000000 --- a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -""" -This file is part of PyCortexMDebug - -PyCortexMDebug is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -PyCortexMDebug is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with PyCortexMDebug. If not, see . -""" - -import gdb -import struct - -DWT_CTRL = 0xE0001000 -DWT_CYCCNT = 0xE0001004 -DWT_CPICNT = 0xE0001008 -DWT_EXTCNT = 0xE000100C -DWT_SLEEPCNT = 0xE0001010 -DWT_LSUCNT = 0xE0001014 -DWT_FOLDCNT = 0xE0001018 -DWT_PCSR = 0xE000101C - -prefix = "dwt : " - - -class DWT(gdb.Command): - clk = None - is_init = False - - def __init__(self): - gdb.Command.__init__(self, "dwt", gdb.COMMAND_DATA) - - @staticmethod - def read(address, bits=32): - """Read from memory (using print) and return an integer""" - value = gdb.selected_inferior().read_memory(address, bits / 8) - return struct.unpack_from(" 1: - if s[1][:2] == "en": - self.cyccnt_en() - elif s[1][0] == "r": - self.cyccnt_reset() - elif s[1][0] == "d": - self.cyccnt_dis() - gdb.write( - prefix - + "CYCCNT ({}): ".format("ON" if (self.read(DWT_CTRL) & 1) else "OFF") - + self.cycles_str(self.read(DWT_CYCCNT)) - ) - elif s[0] == "reset": - if len(s) > 1: - if s[1] == "cyccnt": - self.cyccnt_reset() - gdb.write(prefix + "CYCCNT reset\n") - if s[1] == "counters": - self.cyccnt_reset() - gdb.write(prefix + "CYCCNT reset\n") - else: - self.cyccnt_reset() - gdb.write(prefix + "CYCCNT reset\n") - else: - # Reset everything - self.cyccnt_reset() - gdb.write(prefix + "CYCCNT reset\n") - elif s[0] == "configclk": - if len(s) == 2: - try: - self.clk = float(s[1]) - except: - self.print_help() - else: - self.print_help() - else: - # Try to figure out what stupid went on here - gdb.write(args) - self.print_help() - - @staticmethod - def complete(text, word): - text = str(text).lower() - s = text.split(" ") - - commands = ["configclk", "reset", "cyccnt"] - reset_commands = ["counters", "cyccnt"] - cyccnt_commands = ["enable", "reset", "disable"] - - if len(s) == 1: - return filter(lambda x: x.startswith(s[0]), commands) - - if len(s) == 2: - if s[0] == "reset": - return filter(lambda x: x.startswith(s[1]), reset_commands) - if s[0] == "cyccnt": - return filter(lambda x: x.startswith(s[1]), cyccnt_commands) - - def cycles_str(self, cycles): - if self.clk: - return "%d cycles, %.3es\n" % (cycles, cycles * 1.0 / self.clk) - else: - return "%d cycles" - - def cyccnt_en(self): - self.write(DWT_CTRL, self.read(DWT_CTRL) | 1) - - def cyccnt_dis(self): - self.write(DWT_CTRL, self.read(DWT_CTRL) & 0xFFFFFFFE) - - def cyccnt_reset(self, value=0): - self.write(DWT_CYCCNT, value) - - def cpicnt_reset(self, value=0): - self.write(DWT_CPICNT, value & 0xFF) - - @staticmethod - def print_help(): - gdb.write("Usage:\n") - gdb.write("=========\n") - gdb.write("dwt:\n") - gdb.write("\tList available peripherals\n") - gdb.write("dwt configclk [Hz]:\n") - gdb.write("\tSet clock for rendering time values in seconds\n") - gdb.write("dwt reset:\n") - gdb.write("\tReset everything in DWT\n") - gdb.write("dwt reset counters:\n") - gdb.write("\tReset all DWT counters\n") - gdb.write("dwt cyccnt\n") - gdb.write("\tDisplay the cycle count\n") - gdb.write("\td(default):decimal, x: hex, o: octal, b: binary\n") - return - - -# Registers our class to GDB when sourced: -DWT() diff --git a/debug/PyCortexMDebug/cmdebug/x2d.py b/debug/PyCortexMDebug/cmdebug/x2d.py deleted file mode 100644 index fc3f185db..000000000 --- a/debug/PyCortexMDebug/cmdebug/x2d.py +++ /dev/null @@ -1,586 +0,0 @@ -#!/usr/bin/env python -"Makes working with XML feel like you are working with JSON" - -try: - from defusedexpat import pyexpat as expat -except ImportError: - from xml.parsers import expat - -from xml.sax.saxutils import XMLGenerator -from xml.sax.xmlreader import AttributesImpl - -try: # pragma no cover - from cStringIO import StringIO -except ImportError: # pragma no cover - try: - from StringIO import StringIO - except ImportError: - from io import StringIO - -from inspect import isgenerator - - -class ObjectDict(dict): - def __getattr__(self, name): - if name in self: - return self[name] - else: - raise AttributeError("No such attribute: " + name) - - -try: # pragma no cover - _basestring = basestring -except NameError: # pragma no cover - _basestring = str -try: # pragma no cover - _unicode = unicode -except NameError: # pragma no cover - _unicode = str - -__author__ = "Martin Blech" -__version__ = "0.12.0" -__license__ = "MIT" - - -class ParsingInterrupted(Exception): - pass - - -class _DictSAXHandler(object): - def __init__( - self, - item_depth=0, - item_callback=lambda *args: True, - xml_attribs=True, - attr_prefix="@", - cdata_key="#text", - force_cdata=False, - cdata_separator="", - postprocessor=None, - dict_constructor=ObjectDict, - strip_whitespace=True, - namespace_separator=":", - namespaces=None, - force_list=None, - comment_key="#comment", - ): - self.path = [] - self.stack = [] - self.data = [] - self.item = None - self.item_depth = item_depth - self.xml_attribs = xml_attribs - self.item_callback = item_callback - self.attr_prefix = attr_prefix - self.cdata_key = cdata_key - self.force_cdata = force_cdata - self.cdata_separator = cdata_separator - self.postprocessor = postprocessor - self.dict_constructor = dict_constructor - self.strip_whitespace = strip_whitespace - self.namespace_separator = namespace_separator - self.namespaces = namespaces - self.namespace_declarations = ObjectDict() - self.force_list = force_list - self.comment_key = comment_key - - def _build_name(self, full_name): - if self.namespaces is None: - return full_name - i = full_name.rfind(self.namespace_separator) - if i == -1: - return full_name - namespace, name = full_name[:i], full_name[i + 1 :] - try: - short_namespace = self.namespaces[namespace] - except KeyError: - short_namespace = namespace - if not short_namespace: - return name - else: - return self.namespace_separator.join((short_namespace, name)) - - def _attrs_to_dict(self, attrs): - if isinstance(attrs, dict): - return attrs - return self.dict_constructor(zip(attrs[0::2], attrs[1::2])) - - def startNamespaceDecl(self, prefix, uri): - self.namespace_declarations[prefix or ""] = uri - - def startElement(self, full_name, attrs): - name = self._build_name(full_name) - attrs = self._attrs_to_dict(attrs) - if attrs and self.namespace_declarations: - attrs["xmlns"] = self.namespace_declarations - self.namespace_declarations = ObjectDict() - self.path.append((name, attrs or None)) - if len(self.path) > self.item_depth: - self.stack.append((self.item, self.data)) - if self.xml_attribs: - attr_entries = [] - for key, value in attrs.items(): - key = self.attr_prefix + self._build_name(key) - if self.postprocessor: - entry = self.postprocessor(self.path, key, value) - else: - entry = (key, value) - if entry: - attr_entries.append(entry) - attrs = self.dict_constructor(attr_entries) - else: - attrs = None - self.item = attrs or None - self.data = [] - - def endElement(self, full_name): - name = self._build_name(full_name) - if len(self.path) == self.item_depth: - item = self.item - if item is None: - item = None if not self.data else self.cdata_separator.join(self.data) - - should_continue = self.item_callback(self.path, item) - if not should_continue: - raise ParsingInterrupted() - if len(self.stack): - data = None if not self.data else self.cdata_separator.join(self.data) - item = self.item - self.item, self.data = self.stack.pop() - if self.strip_whitespace and data: - data = data.strip() or None - if data and self.force_cdata and item is None: - item = self.dict_constructor() - if item is not None: - if data: - self.push_data(item, self.cdata_key, data) - self.item = self.push_data(self.item, name, item) - else: - self.item = self.push_data(self.item, name, data) - else: - self.item = None - self.data = [] - self.path.pop() - - def characters(self, data): - if not self.data: - self.data = [data] - else: - self.data.append(data) - - def comments(self, data): - if self.strip_whitespace: - data = data.strip() - self.item = self.push_data(self.item, self.comment_key, data) - - def push_data(self, item, key, data): - if self.postprocessor is not None: - result = self.postprocessor(self.path, key, data) - if result is None: - return item - key, data = result - if item is None: - item = self.dict_constructor() - try: - value = item[key] - if isinstance(value, list): - value.append(data) - else: - item[key] = [value, data] - except KeyError: - if self._should_force_list(key, data): - item[key] = [data] - else: - item[key] = data - return item - - def _should_force_list(self, key, value): - if not self.force_list: - return False - if isinstance(self.force_list, bool): - return self.force_list - try: - return key in self.force_list - except TypeError: - return self.force_list(self.path[:-1], key, value) - - -def parse( - xml_input, - encoding=None, - expat=expat, - process_namespaces=False, - namespace_separator=":", - disable_entities=True, - process_comments=False, - **kwargs -): - """Parse the given XML input and convert it into a dictionary. - - `xml_input` can either be a `string`, a file-like object, or a generator of strings. - - If `xml_attribs` is `True`, element attributes are put in the dictionary - among regular child elements, using `@` as a prefix to avoid collisions. If - set to `False`, they are just ignored. - - Simple example:: - - >>> import xmltodict - >>> doc = xmltodict.parse(\"\"\" - ... - ... 1 - ... 2 - ... - ... \"\"\") - >>> doc['a']['@prop'] - u'x' - >>> doc['a']['b'] - [u'1', u'2'] - - If `item_depth` is `0`, the function returns a dictionary for the root - element (default behavior). Otherwise, it calls `item_callback` every time - an item at the specified depth is found and returns `None` in the end - (streaming mode). - - The callback function receives two parameters: the `path` from the document - root to the item (name-attribs pairs), and the `item` (dict). If the - callback's return value is false-ish, parsing will be stopped with the - :class:`ParsingInterrupted` exception. - - Streaming example:: - - >>> def handle(path, item): - ... print('path:%s item:%s' % (path, item)) - ... return True - ... - >>> xmltodict.parse(\"\"\" - ... - ... 1 - ... 2 - ... \"\"\", item_depth=2, item_callback=handle) - path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:1 - path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:2 - - The optional argument `postprocessor` is a function that takes `path`, - `key` and `value` as positional arguments and returns a new `(key, value)` - pair where both `key` and `value` may have changed. Usage example:: - - >>> def postprocessor(path, key, value): - ... try: - ... return key + ':int', int(value) - ... except (ValueError, TypeError): - ... return key, value - >>> xmltodict.parse('12x', - ... postprocessor=postprocessor) - ObjectDict([(u'a', ObjectDict([(u'b:int', [1, 2]), (u'b', u'x')]))]) - - You can pass an alternate version of `expat` (such as `defusedexpat`) by - using the `expat` parameter. E.g: - - >>> import defusedexpat - >>> xmltodict.parse('hello', expat=defusedexpat.pyexpat) - ObjectDict([(u'a', u'hello')]) - - You can use the force_list argument to force lists to be created even - when there is only a single child of a given level of hierarchy. The - force_list argument is a tuple of keys. If the key for a given level - of hierarchy is in the force_list argument, that level of hierarchy - will have a list as a child (even if there is only one sub-element). - The index_keys operation takes precedence over this. This is applied - after any user-supplied postprocessor has already run. - - For example, given this input: - - - host1 - Linux - - - em0 - 10.0.0.1 - - - - - - If called with force_list=('interface',), it will produce - this dictionary: - {'servers': - {'server': - {'name': 'host1', - 'os': 'Linux'}, - 'interfaces': - {'interface': - [ {'name': 'em0', 'ip_address': '10.0.0.1' } ] } } } - - `force_list` can also be a callable that receives `path`, `key` and - `value`. This is helpful in cases where the logic that decides whether - a list should be forced is more complex. - - - If `process_comment` is `True` then comment will be added with comment_key - (default=`'#comment'`) to then tag which contains comment - - For example, given this input: - - - - - - 1 - - 2 - - - - If called with process_comment=True, it will produce - this dictionary: - 'a': { - 'b': { - '#comment': 'b comment', - 'c': { - - '#comment': 'c comment', - '#text': '1', - }, - 'd': '2', - }, - } - """ - handler = _DictSAXHandler(namespace_separator=namespace_separator, **kwargs) - if isinstance(xml_input, _unicode): - if not encoding: - encoding = "utf-8" - xml_input = xml_input.encode(encoding) - if not process_namespaces: - namespace_separator = None - parser = expat.ParserCreate(encoding, namespace_separator) - try: - parser.ordered_attributes = True - except AttributeError: - # Jython's expat does not support ordered_attributes - pass - parser.StartNamespaceDeclHandler = handler.startNamespaceDecl - parser.StartElementHandler = handler.startElement - parser.EndElementHandler = handler.endElement - parser.CharacterDataHandler = handler.characters - if process_comments: - parser.CommentHandler = handler.comments - parser.buffer_text = True - if disable_entities: - try: - # Attempt to disable DTD in Jython's expat parser (Xerces-J). - feature = "http://apache.org/xml/features/disallow-doctype-decl" - parser._reader.setFeature(feature, True) - except AttributeError: - # For CPython / expat parser. - # Anything not handled ends up here and entities aren't expanded. - parser.DefaultHandler = lambda x: None - # Expects an integer return; zero means failure -> expat.ExpatError. - parser.ExternalEntityRefHandler = lambda *x: 1 - if hasattr(xml_input, "read"): - parser.ParseFile(xml_input) - elif isgenerator(xml_input): - for chunk in xml_input: - parser.Parse(chunk, False) - parser.Parse(b"", True) - else: - parser.Parse(xml_input, True) - return handler.item - - -def _process_namespace(name, namespaces, ns_sep=":", attr_prefix="@"): - if not namespaces: - return name - try: - ns, name = name.rsplit(ns_sep, 1) - except ValueError: - pass - else: - ns_res = namespaces.get(ns.strip(attr_prefix)) - name = ( - "{}{}{}{}".format( - attr_prefix if ns.startswith(attr_prefix) else "", ns_res, ns_sep, name - ) - if ns_res - else name - ) - return name - - -def _emit( - key, - value, - content_handler, - attr_prefix="@", - cdata_key="#text", - depth=0, - preprocessor=None, - pretty=False, - newl="\n", - indent="\t", - namespace_separator=":", - namespaces=None, - full_document=True, - expand_iter=None, -): - key = _process_namespace(key, namespaces, namespace_separator, attr_prefix) - if preprocessor is not None: - result = preprocessor(key, value) - if result is None: - return - key, value = result - if ( - not hasattr(value, "__iter__") - or isinstance(value, _basestring) - or isinstance(value, dict) - ): - value = [value] - for index, v in enumerate(value): - if full_document and depth == 0 and index > 0: - raise ValueError("document with multiple roots") - if v is None: - v = ObjectDict() - elif isinstance(v, bool): - if v: - v = _unicode("true") - else: - v = _unicode("false") - elif not isinstance(v, dict): - if ( - expand_iter - and hasattr(v, "__iter__") - and not isinstance(v, _basestring) - ): - v = ObjectDict(((expand_iter, v),)) - else: - v = _unicode(v) - if isinstance(v, _basestring): - v = ObjectDict(((cdata_key, v),)) - cdata = None - attrs = ObjectDict() - children = [] - for ik, iv in v.items(): - if ik == cdata_key: - cdata = iv - continue - if ik.startswith(attr_prefix): - ik = _process_namespace( - ik, namespaces, namespace_separator, attr_prefix - ) - if ik == "@xmlns" and isinstance(iv, dict): - for k, v in iv.items(): - attr = "xmlns{}".format(":{}".format(k) if k else "") - attrs[attr] = _unicode(v) - continue - if not isinstance(iv, _unicode): - iv = _unicode(iv) - attrs[ik[len(attr_prefix) :]] = iv - continue - children.append((ik, iv)) - if pretty: - content_handler.ignorableWhitespace(depth * indent) - content_handler.startElement(key, AttributesImpl(attrs)) - if pretty and children: - content_handler.ignorableWhitespace(newl) - for child_key, child_value in children: - _emit( - child_key, - child_value, - content_handler, - attr_prefix, - cdata_key, - depth + 1, - preprocessor, - pretty, - newl, - indent, - namespaces=namespaces, - namespace_separator=namespace_separator, - expand_iter=expand_iter, - ) - if cdata is not None: - content_handler.characters(cdata) - if pretty and children: - content_handler.ignorableWhitespace(depth * indent) - content_handler.endElement(key) - if pretty and depth: - content_handler.ignorableWhitespace(newl) - - -def unparse( - input_dict, - output=None, - encoding="utf-8", - full_document=True, - short_empty_elements=False, - **kwargs -): - """Emit an XML document for the given `input_dict` (reverse of `parse`). - - The resulting XML document is returned as a string, but if `output` (a - file-like object) is specified, it is written there instead. - - Dictionary keys prefixed with `attr_prefix` (default=`'@'`) are interpreted - as XML node attributes, whereas keys equal to `cdata_key` - (default=`'#text'`) are treated as character data. - - The `pretty` parameter (default=`False`) enables pretty-printing. In this - mode, lines are terminated with `'\n'` and indented with `'\t'`, but this - can be customized with the `newl` and `indent` parameters. - - """ - if full_document and len(input_dict) != 1: - raise ValueError("Document must have exactly one root.") - must_return = False - if output is None: - output = StringIO() - must_return = True - if short_empty_elements: - content_handler = XMLGenerator(output, encoding, True) - else: - content_handler = XMLGenerator(output, encoding) - if full_document: - content_handler.startDocument() - for key, value in input_dict.items(): - _emit(key, value, content_handler, full_document=full_document, **kwargs) - if full_document: - content_handler.endDocument() - if must_return: - value = output.getvalue() - try: # pragma no cover - value = value.decode(encoding) - except AttributeError: # pragma no cover - pass - return value - - -if __name__ == "__main__": # pragma: no cover - import sys - import marshal - - try: - stdin = sys.stdin.buffer - stdout = sys.stdout.buffer - except AttributeError: - stdin = sys.stdin - stdout = sys.stdout - - (item_depth,) = sys.argv[1:] - item_depth = int(item_depth) - - def handle_item(path, item): - marshal.dump((path, item), stdout) - return True - - try: - root = parse( - stdin, - item_depth=item_depth, - item_callback=handle_item, - dict_constructor=dict, - ) - if item_depth == 0: - handle_item([], root) - except KeyboardInterrupt: - pass diff --git a/debug/FreeRTOS/FreeRTOS.py b/scripts/debug/FreeRTOS/FreeRTOS.py similarity index 99% rename from debug/FreeRTOS/FreeRTOS.py rename to scripts/debug/FreeRTOS/FreeRTOS.py index 036e18f31..0eb7e5f8d 100644 --- a/debug/FreeRTOS/FreeRTOS.py +++ b/scripts/debug/FreeRTOS/FreeRTOS.py @@ -29,7 +29,6 @@ from FreeRTOSgdb.GDBCommands import ShowQueueInfo class Scheduler: def __init__(self): - self._blocked = ListInspector("xSuspendedTaskList") self._delayed1 = ListInspector("xDelayedTaskList1") self._delayed2 = ListInspector("xDelayedTaskList2") diff --git a/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py similarity index 100% rename from debug/FreeRTOS/FreeRTOSgdb/EventGroup.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/EventGroup.py diff --git a/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py similarity index 99% rename from debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py index ba811e3e1..5564502ec 100644 --- a/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/GDBCommands.py @@ -61,7 +61,6 @@ class ShowQueueInfo(gdb.Command): if maxCount == 0: print(outputFmt % (q.GetName(), q.GetQueueMessagesWaiting(), "", "")) else: - for i in range(0, maxCount): txName = "" if i < len(sendList): diff --git a/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py similarity index 99% rename from debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py index 1682c9176..c13457017 100644 --- a/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/HandleRegistry.py @@ -48,7 +48,6 @@ class HandleRegistry: print("%d: %3s %16s" % (i, h, name)) def FilterBy(self, qMode): - """Retrieve a List of Mutex Queue Handles""" resp = [] for i in range(self._minIndex, self._maxIndex): diff --git a/debug/FreeRTOS/FreeRTOSgdb/List.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/List.py similarity index 99% rename from debug/FreeRTOS/FreeRTOSgdb/List.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/List.py index 62aa9dc9a..575bdc525 100644 --- a/debug/FreeRTOS/FreeRTOSgdb/List.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/List.py @@ -56,7 +56,6 @@ class ListInspector: of some of the TCB Task lists. """ if self._list != None: - CastType = None if CastTypeStr != None: if type(CastTypeStr) == str: @@ -73,7 +72,6 @@ class ListInspector: index = self._list["pxIndex"] if numElems > 0 and numElems < 200: - if startElem == 0: curr = index else: diff --git a/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py similarity index 99% rename from debug/FreeRTOS/FreeRTOSgdb/QueueTools.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py index 49a780db3..a35f0894f 100644 --- a/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py @@ -47,7 +47,6 @@ QueueMode.Map = QueueMap class QueueInspector: - QueueType = gdb.lookup_type("Queue_t") def __init__(self, handle): diff --git a/debug/FreeRTOS/FreeRTOSgdb/Task.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py similarity index 99% rename from debug/FreeRTOS/FreeRTOSgdb/Task.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py index 04da3bbcd..d3078fdc9 100644 --- a/debug/FreeRTOS/FreeRTOSgdb/Task.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/Task.py @@ -11,7 +11,6 @@ import gdb class TaskInspector: - TCBType = gdb.lookup_type("TCB_t") def __init__(self, handle): diff --git a/debug/FreeRTOS/FreeRTOSgdb/Types.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/Types.py similarity index 100% rename from debug/FreeRTOS/FreeRTOSgdb/Types.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/Types.py diff --git a/debug/FreeRTOS/FreeRTOSgdb/__init__.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/__init__.py similarity index 100% rename from debug/FreeRTOS/FreeRTOSgdb/__init__.py rename to scripts/debug/FreeRTOS/FreeRTOSgdb/__init__.py diff --git a/debug/FreeRTOS/LICENSE b/scripts/debug/FreeRTOS/LICENSE similarity index 100% rename from debug/FreeRTOS/LICENSE rename to scripts/debug/FreeRTOS/LICENSE diff --git a/debug/FreeRTOS/README.md b/scripts/debug/FreeRTOS/README.md similarity index 100% rename from debug/FreeRTOS/README.md rename to scripts/debug/FreeRTOS/README.md diff --git a/debug/PyCortexMDebug/LICENSE b/scripts/debug/PyCortexMDebug/LICENSE similarity index 100% rename from debug/PyCortexMDebug/LICENSE rename to scripts/debug/PyCortexMDebug/LICENSE diff --git a/debug/PyCortexMDebug/PyCortexMDebug.py b/scripts/debug/PyCortexMDebug/PyCortexMDebug.py similarity index 96% rename from debug/PyCortexMDebug/PyCortexMDebug.py rename to scripts/debug/PyCortexMDebug/PyCortexMDebug.py index 6533535c3..fd322b5a6 100644 --- a/debug/PyCortexMDebug/PyCortexMDebug.py +++ b/scripts/debug/PyCortexMDebug/PyCortexMDebug.py @@ -28,7 +28,5 @@ directory = path.abspath(directory) sys.path.append(directory) from cmdebug.svd_gdb import LoadSVD -from cmdebug.dwt_gdb import DWT -DWT() LoadSVD() diff --git a/scripts/debug/PyCortexMDebug/README.md b/scripts/debug/PyCortexMDebug/README.md new file mode 100644 index 000000000..0a5764b02 --- /dev/null +++ b/scripts/debug/PyCortexMDebug/README.md @@ -0,0 +1,35 @@ +PyCortexMDebug +============== + +## SVD + +ARM defines an SVD (System View Description) file format in its CMSIS standard as a means for Cortex-M-based chip manufacturers to provide a common description of peripherals, registers, and register fields. You can download SVD files for different manufacturers [here](http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php). + +The implementation consists of two components -- An lxml-based parser module (pysvd) and a GDB file (gdb_svd). I haven't yet worked out a perfect workflow for this, though it's quite easy to use when you already tend to have a GDB initialization file for starting up OpenOCD and the like. However your workflow works, just make sure to, in GDB: + + source gdb_svd.py + svd_load [your_svd_file].svd + +These files can be huge so it might take a second or two. Anyways, after that, you can do + + svd + +to list available peripherals with descriptions. Or you can do + + svd [some_peripheral_name] + +to see all of the registers (with their values) for a given peripheral. For more details, run + + svd [some_peripheral_name] [some_register_name] + +to see all of the field values with descriptions. + +You can add format modifiers like: + +* `svd/x` will display values in hex +* `svd/o` will display values in octal +* `svd/t` or `svd/b` will display values in binary +* `svd/a` will display values in hex and try to resolve symbols from the values + +All field values are displayed at the correct lengths as provided by the SVD files. +Also, tab completion exists for nearly everything! When in doubt, run `svd help`. diff --git a/debug/PyCortexMDebug/cmdebug/__init__.py b/scripts/debug/PyCortexMDebug/cmdebug/__init__.py similarity index 100% rename from debug/PyCortexMDebug/cmdebug/__init__.py rename to scripts/debug/PyCortexMDebug/cmdebug/__init__.py diff --git a/debug/PyCortexMDebug/cmdebug/svd.py b/scripts/debug/PyCortexMDebug/cmdebug/svd.py similarity index 89% rename from debug/PyCortexMDebug/cmdebug/svd.py rename to scripts/debug/PyCortexMDebug/cmdebug/svd.py index f4a884bb4..a25e69bfb 100755 --- a/debug/PyCortexMDebug/cmdebug/svd.py +++ b/scripts/debug/PyCortexMDebug/cmdebug/svd.py @@ -16,15 +16,14 @@ You should have received a copy of the GNU General Public License along with PyCortexMDebug. If not, see . """ -from collections import OrderedDict -from . import x2d - -import traceback -import warnings -import pickle +import lxml.objectify as objectify import sys +from collections import OrderedDict import os +import pickle +import traceback import re +import warnings class SmartDict: @@ -127,31 +126,26 @@ class SVDFile: def __init__(self, fname): """ + Args: fname: Filename for the SVD file """ + f = objectify.parse(os.path.expanduser(fname)) + root = f.getroot() + periph = root.peripherals.getchildren() self.peripherals = SmartDict() self.base_address = 0 - xml_file_name = os.path.expanduser(fname) - pickle_file_name = xml_file_name + ".pickle" - root = None - if os.path.exists(pickle_file_name): - print("Loading pickled SVD") - root = pickle.load(open(pickle_file_name, "rb")) - else: - print("Loading XML SVD and pickling it") - root = x2d.parse(open(xml_file_name, "rb")) - pickle.dump(root, open(pickle_file_name, "wb"), pickle.HIGHEST_PROTOCOL) - print("Processing SVD tree") # XML elements - for p in root["device"]["peripherals"]["peripheral"]: + for p in periph: try: - self.peripherals[p["name"]] = SVDPeripheral(p, self) + if p.tag == "peripheral": + self.peripherals[str(p.name)] = SVDPeripheral(p, self) + else: + # This is some other tag + pass except SVDNonFatalError as e: - # print(e) - pass - print("SVD Ready") + print(e) def add_register(parent, node): @@ -271,11 +265,11 @@ class SVDPeripheral: self.parent_base_address = parent.base_address # Look for a base address, as it is required - if "baseAddress" not in svd_elem: + if not hasattr(svd_elem, "baseAddress"): raise SVDNonFatalError("Periph without base address") self.base_address = int(str(svd_elem.baseAddress), 0) - if "@derivedFrom" in svd_elem: - derived_from = svd_elem["@derivedFrom"] + if "derivedFrom" in svd_elem.attrib: + derived_from = svd_elem.attrib["derivedFrom"] try: self.name = str(svd_elem.name) except AttributeError: @@ -301,14 +295,16 @@ class SVDPeripheral: self.clusters = SmartDict() if hasattr(svd_elem, "registers"): - if "register" in svd_elem.registers: - for r in svd_elem.registers.register: - if isinstance(r, x2d.ObjectDict): - add_register(self, r) - if "cluster" in svd_elem.registers: - for c in svd_elem.registers.cluster: - if isinstance(c, x2d.ObjectDict): - add_cluster(self, c) + registers = [ + r + for r in svd_elem.registers.getchildren() + if r.tag in ["cluster", "register"] + ] + for r in registers: + if r.tag == "cluster": + add_cluster(self, r) + elif r.tag == "register": + add_register(self, r) def refactor_parent(self, parent): self.parent_base_address = parent.base_address @@ -342,11 +338,11 @@ class SVDPeripheralRegister: else: self.size = 0x20 self.fields = SmartDict() - if "fields" in svd_elem: + if hasattr(svd_elem, "fields"): # Filter fields to only consider those of tag "field" - for f in svd_elem.fields.field: - if isinstance(f, x2d.ObjectDict): - self.fields[str(f.name)] = SVDPeripheralRegisterField(f, self) + fields = [f for f in svd_elem.fields.getchildren() if f.tag == "field"] + for f in fields: + self.fields[str(f.name)] = SVDPeripheralRegisterField(f, self) def refactor_parent(self, parent): self.parent_base_address = parent.base_address diff --git a/debug/PyCortexMDebug/cmdebug/svd_gdb.py b/scripts/debug/PyCortexMDebug/cmdebug/svd_gdb.py similarity index 100% rename from debug/PyCortexMDebug/cmdebug/svd_gdb.py rename to scripts/debug/PyCortexMDebug/cmdebug/svd_gdb.py diff --git a/debug/STM32WB55_CM4.svd b/scripts/debug/STM32WB55_CM4.svd similarity index 100% rename from debug/STM32WB55_CM4.svd rename to scripts/debug/STM32WB55_CM4.svd diff --git a/debug/flipperapps.py b/scripts/debug/flipperapps.py similarity index 100% rename from debug/flipperapps.py rename to scripts/debug/flipperapps.py diff --git a/debug/flipperversion.py b/scripts/debug/flipperversion.py similarity index 100% rename from debug/flipperversion.py rename to scripts/debug/flipperversion.py diff --git a/debug/fw.jflash b/scripts/debug/fw.jflash similarity index 100% rename from debug/fw.jflash rename to scripts/debug/fw.jflash diff --git a/debug/gdbinit b/scripts/debug/gdbinit similarity index 100% rename from debug/gdbinit rename to scripts/debug/gdbinit diff --git a/debug/stm32wbx.cfg b/scripts/debug/stm32wbx.cfg similarity index 100% rename from debug/stm32wbx.cfg rename to scripts/debug/stm32wbx.cfg diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index 58e73e9c9..d46ecd8f3 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -18,7 +18,7 @@ def GetDevices(env): def generate(env, **kw): env.AddMethod(GetDevices) env.SetDefault( - FBT_DEBUG_DIR="${ROOT_DIR}/debug", + FBT_DEBUG_DIR="${FBT_SCRIPT_DIR}/debug", ) if (adapter_serial := env.subst("$OPENOCD_ADAPTER_SERIAL")) != "auto": diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index 1657feab9..d2d1d2f49 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -170,7 +170,6 @@ class Main(App): "update.dir", "sdk_headers.dir", "lib.dir", - "debug.dir", "scripts.dir", ) diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 3f623ebc8..4dd1fb5b9 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -186,6 +186,33 @@ dist_env.PhonyTarget( FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(dist_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")), ) +# Debug alien elf +debug_other_opts = [ + "-ex", + "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py", + "-ex", + "source ${FBT_DEBUG_DIR}/flipperversion.py", + "-ex", + "fw-version", +] + +dist_env.PhonyTarget( + "debug_other", + "${GDBPYCOM}", + GDBOPTS="${GDBOPTS_BASE}", + GDBREMOTE="${OPENOCD_GDB_PIPE}", + GDBPYOPTS=debug_other_opts, +) + +dist_env.PhonyTarget( + "debug_other_blackmagic", + "${GDBPYCOM}", + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBREMOTE="${BLACKMAGIC_ADDR}", + GDBPYOPTS=debug_other_opts, +) + + dist_env.PhonyTarget( "flash_blackmagic", "$GDB $GDBOPTS $SOURCES $GDBFLASH", diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py index 47f4afec4..0038b66a3 100644 --- a/scripts/ufbt/site_tools/ufbt_state.py +++ b/scripts/ufbt/site_tools/ufbt_state.py @@ -78,10 +78,8 @@ def generate(env, **kw): env.SetDefault( # Paths SDK_DEFINITION=env.File(sdk_data["sdk_symbols"]), - FBT_DEBUG_DIR=pathlib.Path( - sdk_current_sdk_dir_node.Dir(sdk_components["debug.dir"]).abspath - ).as_posix(), FBT_SCRIPT_DIR=scripts_dir, + FBT_DEBUG_DIR=scripts_dir.Dir("debug"), LIBPATH=sdk_current_sdk_dir_node.Dir(sdk_components["lib.dir"]), FW_ELF=sdk_current_sdk_dir_node.File(sdk_components["firmware.elf"]), FW_BIN=sdk_current_sdk_dir_node.File(sdk_components["full.bin"]), From e1c6e78b2ecdfe6da19c04d4e16b95c7f8247e9f Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Tue, 9 May 2023 02:55:17 +0200 Subject: [PATCH 155/216] added DigitalSequence and PulseReader (#2070) * added DigitalSequence to chain multiple DigitalSignals added PulseReader for hardware assisted digital signal sampling * added send_time option to start a signal at a specific DWT->CYCCNT value * fixed linter errors and undone function renaming * fixed renaming * flagged functions in api_symbols.csv * allow gpio field to stay uninitialized in digital_signal_prepare_arr() * fix test cases to match (expected) implementation * pulse_reader: build as static library Signed-off-by: g3gg0.de * fix starting level detection in pulse_reader * added unit test for pulse_reader * change pulse reader test timings to 1, 10 and 100 ms * fine tuned timings for pulse_reader test * pulse_reader_stop now deinits GPIO as recommended by @gornekich * ran format_py * pulse_reader: remove from API, allow to link with faps Signed-off-by: g3gg0.de * remove unit test for pulse_reader again * pulse_reader: add call to set GPIO pull direction * make structures private, add C implementation of digital_signal_update_dma() * digital_signal/pulse_reader: allow parameters for free to be NULL * digital_signal: show unoptimized and optimized code for digital_signal_update_dma() next to each other * pulse_reader: further optimize assembly code * digital_signal: reduce code complexity of digital_signal_update_dma() by only reconfiguring DMA2 * digital_signal: remove assembly code, limiting the performance but increasing portability * added recovery if the timer already expired * digital_signal: fix memory leak * digital_signal: keep lock until all DMA transfers have finished * DigitalSequence: fix issues with concatenation of same levels and spurious bit flips * DigitalSignal: use cyclic DMA buffer for sequences * update api_symbols.csv * Update api_symbols.csv for f18 target * Patches from @gornekich to fix linter warnings. * Remove some redundant if checks * Remove some magic numbers and reformat. * Remove forced terminating edge. Signed-off-by: g3gg0.de Co-authored-by: gornekich Co-authored-by: Tiernan Messmer Co-authored-by: Aleksandr Kutuzov --- .../unit_tests/nfc/nfc_nfca_signal_long.nfc | 2 +- .../unit_tests/nfc/nfc_nfca_signal_short.nfc | 2 +- firmware/targets/f18/api_symbols.csv | 12 +- firmware/targets/f7/api_symbols.csv | 22 +- firmware/targets/f7/target.json | 1 + lib/SConscript | 3 + lib/digital_signal/digital_signal.c | 648 +++++++++++++++--- lib/digital_signal/digital_signal.h | 40 +- lib/pulse_reader/SConscript | 27 + lib/pulse_reader/pulse_reader.c | 233 +++++++ lib/pulse_reader/pulse_reader.h | 122 ++++ 11 files changed, 1024 insertions(+), 88 deletions(-) create mode 100644 lib/pulse_reader/SConscript create mode 100644 lib/pulse_reader/pulse_reader.c create mode 100644 lib/pulse_reader/pulse_reader.h diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc b/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc index fae69cb5c..dd6a2ff8e 100644 --- a/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc +++ b/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc @@ -3,4 +3,4 @@ Version: 1 Data length: 18 Plain data: f1 99 41 43 a1 2f 23 01 de f3 c5 8d 91 4b 1e 50 4a c9 Timings length: 1304 -Timings: 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 640 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 0 +Timings: 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 640 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc b/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc index 3b7e2d9e9..f447fca26 100644 --- a/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc +++ b/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc @@ -3,4 +3,4 @@ Version: 1 Data length: 4 Plain data: 14 d8 a0 c9 Timings length: 296 -Timings: 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 36 37 37 37 37 36 37 0 +Timings: 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 36 37 37 37 37 36 37 37 diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 7a892e1cc..828c77166 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,+,26.1,, +Version,+,26.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -156,6 +156,7 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, @@ -1575,6 +1576,15 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t" Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" +Function,-,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t" +Function,-,pulse_reader_free,void,PulseReader* +Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int" +Function,-,pulse_reader_samples,uint32_t,PulseReader* +Function,-,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" +Function,-,pulse_reader_set_pull,void,"PulseReader*, GpioPull" +Function,-,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" +Function,-,pulse_reader_start,void,PulseReader* +Function,-,pulse_reader_stop,void,PulseReader* Function,-,putc,int,"int, FILE*" Function,-,putc_unlocked,int,"int, FILE*" Function,-,putchar,int,int diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6cb421a1b..d73a1c7bc 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,26.1,, +Version,+,26.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -175,6 +175,7 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/subghz/blocks/const.h,, Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, @@ -738,6 +739,16 @@ Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, u Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" Function,-,difftime,double,"time_t, time_t" +Function,-,digital_sequence_add,void,"DigitalSequence*, uint8_t" +Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" +Function,-,digital_sequence_clear,void,DigitalSequence* +Function,-,digital_sequence_free,void,DigitalSequence* +Function,-,digital_sequence_send,_Bool,DigitalSequence* +Function,-,digital_sequence_set_sendtime,void,"DigitalSequence*, uint32_t" +Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*" +Function,-,digital_sequence_timebase_correction,void,"DigitalSequence*, float" +Function,-,digital_signal_add,void,"DigitalSignal*, uint32_t" +Function,-,digital_signal_add_pulse,void,"DigitalSignal*, uint32_t, _Bool" Function,-,digital_signal_alloc,DigitalSignal*,uint32_t Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*" Function,-,digital_signal_free,void,DigitalSignal* @@ -2168,6 +2179,15 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t" Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" +Function,-,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t" +Function,-,pulse_reader_free,void,PulseReader* +Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int" +Function,-,pulse_reader_samples,uint32_t,PulseReader* +Function,-,pulse_reader_set_bittime,void,"PulseReader*, uint32_t" +Function,-,pulse_reader_set_pull,void,"PulseReader*, GpioPull" +Function,-,pulse_reader_set_timebase,void,"PulseReader*, PulseReaderUnit" +Function,-,pulse_reader_start,void,PulseReader* +Function,-,pulse_reader_stop,void,PulseReader* Function,-,putc,int,"int, FILE*" Function,-,putc_unlocked,int,"int, FILE*" Function,-,putchar,int,int diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 4d97ae7d7..c50364453 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -28,6 +28,7 @@ "flipperformat", "toolbox", "nfc", + "pulse_reader", "microtar", "usb_stm32", "st25rfal002", diff --git a/lib/SConscript b/lib/SConscript index b8a36c872..8727746d8 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -4,6 +4,7 @@ env.Append( LINT_SOURCES=[ Dir("app-scened-template"), Dir("digital_signal"), + Dir("pulse_reader"), Dir("drivers"), Dir("flipper_format"), Dir("infrared"), @@ -14,6 +15,7 @@ env.Append( Dir("u8g2"), Dir("update_util"), Dir("print"), + Dir("pulse_reader"), ], ) @@ -93,6 +95,7 @@ libs = env.BuildModules( "mbedtls", "subghz", "nfc", + "pulse_reader", "appframe", "misc", "lfrfid", diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 46ca307a7..51a87d22a 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -1,23 +1,98 @@ #include "digital_signal.h" #include -#include -#include +#include +#include #include -#pragma GCC optimize("O3,unroll-loops,Ofast") +#include +#include + +/* must be on bank B */ +#define DEBUG_OUTPUT gpio_ext_pb3 + +struct ReloadBuffer { + uint32_t* buffer; /* DMA ringbuffer */ + uint32_t size; /* maximum entry count of the ring buffer */ + uint32_t write_pos; /* current buffer write index */ + uint32_t read_pos; /* current buffer read index */ + bool dma_active; +}; + +struct DigitalSequence { + uint8_t signals_size; + bool bake; + uint32_t sequence_used; + uint32_t sequence_size; + DigitalSignal** signals; + uint8_t* sequence; + const GpioPin* gpio; + uint32_t send_time; + bool send_time_active; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; + uint32_t* gpio_buff; + struct ReloadBuffer* dma_buffer; +}; + +struct DigitalSignalInternals { + uint64_t factor; + uint32_t reload_reg_entries; + uint32_t reload_reg_remainder; + uint32_t gpio_buff[2]; + const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; +}; + +#define TAG "DigitalSignal" #define F_TIM (64000000.0) -#define T_TIM 1562 //15.625 ns *100 -#define T_TIM_DIV2 781 //15.625 ns / 2 *100 +#define T_TIM 1562 /* 15.625 ns *100 */ +#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ + +/* maximum entry count of the sequence dma ring buffer */ +#define SEQUENCE_DMA_RINGBUFFER_SIZE 32 +/* maximum number of DigitalSignals in a sequence */ +#define SEQUENCE_SIGNALS_SIZE 32 +/* + * if sequence size runs out from the initial value passed to digital_sequence_alloc + * the size will be increased by this amount and reallocated + */ +#define SEQUENCE_SIZE_REALLOCATE_INCREMENT 256 DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { DigitalSignal* signal = malloc(sizeof(DigitalSignal)); signal->start_level = true; signal->edges_max_cnt = max_edges_cnt; - signal->edge_timings = malloc(max_edges_cnt * sizeof(uint32_t)); - signal->reload_reg_buff = malloc(max_edges_cnt * sizeof(uint32_t)); + signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->edge_cnt = 0; + signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); + + signal->internals = malloc(sizeof(DigitalSignalInternals)); + DigitalSignalInternals* internals = signal->internals; + + internals->factor = 1024 * 1024; + + internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + internals->dma_config_gpio.NbData = 2; + internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -27,6 +102,7 @@ void digital_signal_free(DigitalSignal* signal) { free(signal->edge_timings); free(signal->reload_reg_buff); + free(signal->internals); free(signal); } @@ -37,7 +113,10 @@ bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) { if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) { return false; } - + /* in case there are no edges in our target signal, the signal to append makes the rules */ + if(!signal_a->edge_cnt) { + signal_a->start_level = signal_b->start_level; + } bool end_level = signal_a->start_level; if(signal_a->edge_cnt) { end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2); @@ -72,6 +151,32 @@ uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) { return signal->edge_cnt; } +void digital_signal_add(DigitalSignal* signal, uint32_t ticks) { + furi_assert(signal); + furi_assert(signal->edge_cnt < signal->edges_max_cnt); + + signal->edge_timings[signal->edge_cnt++] = ticks; +} + +void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level) { + furi_assert(signal); + furi_assert(signal->edge_cnt < signal->edges_max_cnt); + + /* virgin signal? add it as the only level */ + if(signal->edge_cnt == 0) { + signal->start_level = level; + signal->edge_timings[signal->edge_cnt++] = ticks; + } else { + bool end_level = signal->start_level ^ !(signal->edge_cnt % 2); + + if(level != end_level) { + signal->edge_timings[signal->edge_cnt++] = ticks; + } else { + signal->edge_timings[signal->edge_cnt - 1] += ticks; + } + } +} + uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { furi_assert(signal); furi_assert(edge_num < signal->edge_cnt); @@ -80,94 +185,473 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { } void digital_signal_prepare_arr(DigitalSignal* signal) { - uint32_t t_signal_rest = signal->edge_timings[0]; - uint32_t r_count_tick_arr = 0; - uint32_t r_rest_div = 0; + furi_assert(signal); - for(size_t i = 0; i < signal->edge_cnt - 1; i++) { - r_count_tick_arr = t_signal_rest / T_TIM; - r_rest_div = t_signal_rest % T_TIM; - t_signal_rest = signal->edge_timings[i + 1] + r_rest_div; + DigitalSignalInternals* internals = signal->internals; - if(r_rest_div < T_TIM_DIV2) { - signal->reload_reg_buff[i] = r_count_tick_arr - 1; + /* set up signal polarities */ + if(internals->gpio) { + uint32_t bit_set = internals->gpio->pin; + uint32_t bit_reset = internals->gpio->pin << 16; + +#ifdef DEBUG_OUTPUT + bit_set |= DEBUG_OUTPUT.pin; + bit_reset |= DEBUG_OUTPUT.pin << 16; +#endif + + if(signal->start_level) { + internals->gpio_buff[0] = bit_set; + internals->gpio_buff[1] = bit_reset; } else { - signal->reload_reg_buff[i] = r_count_tick_arr; - t_signal_rest -= T_TIM; + internals->gpio_buff[0] = bit_reset; + internals->gpio_buff[1] = bit_set; + } + } + + /* set up edge timings */ + internals->reload_reg_entries = 0; + + for(size_t pos = 0; pos < signal->edge_cnt; pos++) { + uint32_t edge_scaled = (internals->factor * signal->edge_timings[pos]) / (1024 * 1024); + uint32_t pulse_duration = edge_scaled + internals->reload_reg_remainder; + if(pulse_duration < 10 || pulse_duration > 10000000) { + FURI_LOG_D( + TAG, + "[prepare] pulse_duration out of range: %lu = %lu * %llu", + pulse_duration, + signal->edge_timings[pos], + internals->factor); + pulse_duration = 100; + } + uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; + internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); + + if(pulse_ticks > 1) { + signal->reload_reg_buff[internals->reload_reg_entries++] = pulse_ticks - 1; } } } -void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { - furi_assert(signal); - furi_assert(gpio); +static void digital_signal_stop_dma() { + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); +} - // Configure gpio as output - furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +static void digital_signal_stop_timer() { + LL_TIM_DisableCounter(TIM2); + LL_TIM_DisableUpdateEvent(TIM2); + LL_TIM_DisableDMAReq_UPDATE(TIM2); +} - // Init gpio buffer and DMA channel - uint16_t gpio_reg = gpio->port->ODR; - uint16_t gpio_buff[2]; - if(signal->start_level) { - gpio_buff[0] = gpio_reg | gpio->pin; - gpio_buff[1] = gpio_reg & ~(gpio->pin); - } else { - gpio_buff[0] = gpio_reg & ~(gpio->pin); - gpio_buff[1] = gpio_reg | gpio->pin; - } - LL_DMA_InitTypeDef dma_config = {}; - dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR); - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_CIRCULAR; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; - dma_config.NbData = 2; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); +static void digital_signal_setup_timer() { + digital_signal_stop_timer(); - // Init timer arr register buffer and DMA channel - digital_signal_prepare_arr(signal); - dma_config.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); - dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config.Mode = LL_DMA_MODE_NORMAL; - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.NbData = signal->edge_cnt - 2; - dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config.Priority = LL_DMA_PRIORITY_HIGH; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); - - // Set up timer LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); - LL_TIM_SetAutoReload(TIM2, 10); + LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); LL_TIM_SetCounter(TIM2, 0); +} + +static void digital_signal_start_timer() { + LL_TIM_EnableCounter(TIM2); LL_TIM_EnableUpdateEvent(TIM2); LL_TIM_EnableDMAReq_UPDATE(TIM2); - - // Start transactions - LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it? - LL_TIM_EnableCounter(TIM2); - - while(!LL_DMA_IsActiveFlag_TC2(DMA1)) - ; - - LL_DMA_ClearFlag_TC1(DMA1); - LL_DMA_ClearFlag_TC2(DMA1); - LL_TIM_DisableCounter(TIM2); - LL_TIM_SetCounter(TIM2, 0); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_TIM_GenerateEvent_UPDATE(TIM2); +} + +static bool digital_signal_setup_dma(DigitalSignal* signal) { + furi_assert(signal); + DigitalSignalInternals* internals = signal->internals; + + if(!signal->internals->reload_reg_entries) { + return false; + } + digital_signal_stop_dma(); + + internals->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)internals->gpio_buff; + internals->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (internals->gpio->port->BSRR); + internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; + internals->dma_config_timer.NbData = signal->internals->reload_reg_entries; + + /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &internals->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &internals->dma_config_timer); + + /* enable both DMA channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + return true; +} + +void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { + furi_assert(signal); + + if(!signal->edge_cnt) { + return; + } + + /* Configure gpio as output */ + signal->internals->gpio = gpio; + furi_hal_gpio_init( + signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + digital_signal_prepare_arr(signal); + + digital_signal_setup_dma(signal); + digital_signal_setup_timer(); + digital_signal_start_timer(); + + while(!LL_DMA_IsActiveFlag_TC2(DMA1)) { + } + + digital_signal_stop_timer(); + digital_signal_stop_dma(); +} + +static void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { + sequence->signals_size = size; + sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); +} + +static void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) { + sequence->sequence_used = 0; + sequence->sequence_size = size; + sequence->sequence = malloc(sequence->sequence_size); + sequence->send_time = 0; + sequence->send_time_active = false; +} + +DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { + furi_assert(gpio); + + DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); + + sequence->gpio = gpio; + sequence->bake = false; + + sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer)); + sequence->dma_buffer->size = SEQUENCE_DMA_RINGBUFFER_SIZE; + sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t)); + + sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + sequence->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + sequence->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + sequence->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + sequence->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + sequence->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + sequence->dma_config_gpio.NbData = 2; + sequence->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + sequence->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + sequence->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + sequence->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; + sequence->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + sequence->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + sequence->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + sequence->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + sequence->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + sequence->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)sequence->dma_buffer->buffer; + sequence->dma_config_timer.NbData = sequence->dma_buffer->size; + sequence->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + sequence->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; + + digital_sequence_alloc_signals(sequence, SEQUENCE_SIGNALS_SIZE); + digital_sequence_alloc_sequence(sequence, size); + + return sequence; +} + +void digital_sequence_free(DigitalSequence* sequence) { + furi_assert(sequence); + + free(sequence->signals); + free(sequence->sequence); + free(sequence->dma_buffer->buffer); + free(sequence->dma_buffer); + free(sequence); +} + +void digital_sequence_set_signal( + DigitalSequence* sequence, + uint8_t signal_index, + DigitalSignal* signal) { + furi_assert(sequence); + furi_assert(signal); + furi_assert(signal_index < sequence->signals_size); + + sequence->signals[signal_index] = signal; + signal->internals->gpio = sequence->gpio; + signal->internals->reload_reg_remainder = 0; + + digital_signal_prepare_arr(signal); +} + +void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) { + furi_assert(sequence); + + sequence->send_time = send_time; + sequence->send_time_active = true; +} + +void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { + furi_assert(sequence); + furi_assert(signal_index < sequence->signals_size); + + if(sequence->sequence_used >= sequence->sequence_size) { + sequence->sequence_size += SEQUENCE_SIZE_REALLOCATE_INCREMENT; + sequence->sequence = realloc(sequence->sequence, sequence->sequence_size); //-V701 + furi_assert(sequence->sequence); + } + + sequence->sequence[sequence->sequence_used++] = signal_index; +} + +static bool digital_sequence_setup_dma(DigitalSequence* sequence) { + furi_assert(sequence); + + digital_signal_stop_dma(); + + sequence->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)sequence->gpio_buff; + sequence->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (sequence->gpio->port->BSRR); + + /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &sequence->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &sequence->dma_config_timer); + + /* enable both DMA channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + return true; +} + +static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { + furi_assert(sequence); + + uint32_t edges = 0; + + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { + uint8_t signal_index = sequence->sequence[pos]; + DigitalSignal* sig = sequence->signals[signal_index]; + + edges += sig->edge_cnt; + } + + DigitalSignal* ret = digital_signal_alloc(edges); + + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { + uint8_t signal_index = sequence->sequence[pos]; + DigitalSignal* sig = sequence->signals[signal_index]; + + digital_signal_append(ret, sig); + } + + return ret; +} + +static void digital_sequence_update_pos(DigitalSequence* sequence) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + dma_buffer->read_pos = dma_buffer->size - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); +} + +static const uint32_t wait_ms = 10; +static const uint32_t wait_ticks = wait_ms * 1000 * 64; + +static void digital_sequence_finish(DigitalSequence* sequence) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + if(dma_buffer->dma_active) { + uint32_t prev_timer = DWT->CYCCNT; + uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + do { + uint32_t last_pos = dma_buffer->read_pos; + + digital_sequence_update_pos(sequence); + + /* we are finished, when the DMA transferred the 0xFFFFFFFF-timer which is the current write_pos */ + if(dma_buffer->read_pos == end_pos) { + break; + } + + if(last_pos != dma_buffer->read_pos) { //-V547 + prev_timer = DWT->CYCCNT; + } + if(DWT->CYCCNT - prev_timer > wait_ticks) { + FURI_LOG_D( + TAG, + "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)", + wait_ms, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + } while(1); + } + + digital_signal_stop_timer(); + digital_signal_stop_dma(); +} + +static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t length) { + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + if(dma_buffer->dma_active) { + uint32_t prev_timer = DWT->CYCCNT; + uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + do { + uint32_t last_pos = dma_buffer->read_pos; + digital_sequence_update_pos(sequence); + + if(dma_buffer->read_pos != end_pos) { + break; + } + + if(last_pos != dma_buffer->read_pos) { //-V547 + prev_timer = DWT->CYCCNT; + } + if(DWT->CYCCNT - prev_timer > wait_ticks) { + FURI_LOG_D( + TAG, + "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)", + wait_ms, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + } while(1); + } + + dma_buffer->buffer[dma_buffer->write_pos] = length; + dma_buffer->write_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; + dma_buffer->buffer[dma_buffer->write_pos] = 0xFFFFFFFF; +} + +bool digital_sequence_send(DigitalSequence* sequence) { + furi_assert(sequence); + + struct ReloadBuffer* dma_buffer = sequence->dma_buffer; + + furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#ifdef DEBUG_OUTPUT + furi_hal_gpio_init(&DEBUG_OUTPUT, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#endif + + if(sequence->bake) { + DigitalSignal* sig = digital_sequence_bake(sequence); + + digital_signal_send(sig, sequence->gpio); + digital_signal_free(sig); + return true; + } + + int32_t remainder = 0; + bool traded_first = false; + + FURI_CRITICAL_ENTER(); + + dma_buffer->dma_active = false; + dma_buffer->buffer[0] = 0xFFFFFFFF; + dma_buffer->read_pos = 0; + dma_buffer->write_pos = 0; + + for(uint32_t seq_pos = 0; seq_pos < sequence->sequence_used; seq_pos++) { + uint8_t signal_index = sequence->sequence[seq_pos]; + DigitalSignal* sig = sequence->signals[signal_index]; + bool last_signal = ((seq_pos + 1) == sequence->sequence_used); + + /* all signals are prepared and we can re-use the GPIO buffer from the fist signal */ + if(seq_pos == 0) { + sequence->gpio_buff = sig->internals->gpio_buff; + } + + for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) { + if(traded_first) { + traded_first = false; + continue; + } + uint32_t pulse_length = 0; + bool last_pulse = ((pulse_pos + 1) == sig->internals->reload_reg_entries); + + pulse_length = sig->reload_reg_buff[pulse_pos]; + + /* when we are too late more than half a tick, make the first edge temporarily longer */ + if(remainder >= T_TIM_DIV2) { + remainder -= T_TIM; + pulse_length += 1; + } + remainder += sig->internals->reload_reg_remainder; + + /* last pulse in that signal and have a next signal? */ + if(last_pulse) { + if((seq_pos + 1) < sequence->sequence_used) { + DigitalSignal* sig_next = sequence->signals[sequence->sequence[seq_pos + 1]]; + + /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ + /* beware, we do not want the level after the last edge, but the last level before that edge */ + bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); + + /* take from the next, add it to the current if they have the same level */ + if(end_level == sig_next->start_level) { + pulse_length += sig_next->reload_reg_buff[0]; + traded_first = true; + } + } + } + + digital_sequence_queue_pulse(sequence, pulse_length); + + /* start transmission when buffer was filled enough */ + bool start_send = sequence->dma_buffer->write_pos >= (sequence->dma_buffer->size - 4); + + /* or it was the last pulse */ + if(last_pulse && last_signal) { + start_send = true; + } + + /* start transmission */ + if(start_send && !dma_buffer->dma_active) { + digital_sequence_setup_dma(sequence); + digital_signal_setup_timer(); + + /* if the send time is specified, wait till the core timer passed beyond that time */ + if(sequence->send_time_active) { + sequence->send_time_active = false; + while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + } + } + digital_signal_start_timer(); + dma_buffer->dma_active = true; + } + } + } + + /* wait until last dma transaction was finished */ + digital_sequence_finish(sequence); + FURI_CRITICAL_EXIT(); + + return true; +} + +void digital_sequence_clear(DigitalSequence* sequence) { + furi_assert(sequence); + + sequence->sequence_used = 0; +} + +void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor) { + for(uint32_t sig_pos = 0; sig_pos < sequence->signals_size; sig_pos++) { + DigitalSignal* signal = sequence->signals[sig_pos]; + + if(signal) { + signal->internals->factor = (uint32_t)(1024 * 1024 * factor); + digital_signal_prepare_arr(signal); + } + } } diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 90905d74b..404d02605 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -10,18 +10,35 @@ extern "C" { #endif -typedef struct { +/* helper for easier signal generation */ +#define DIGITAL_SIGNAL_MS(x) ((x)*100000000UL) +#define DIGITAL_SIGNAL_US(x) ((x)*100000UL) +#define DIGITAL_SIGNAL_NS(x) ((x)*100UL) +#define DIGITAL_SIGNAL_PS(x) ((x) / 10UL) + +/* using an anonymous type for the internals */ +typedef struct DigitalSignalInternals DigitalSignalInternals; + +/* and a public one for accessing user-side fields */ +typedef struct DigitalSignal { bool start_level; uint32_t edge_cnt; uint32_t edges_max_cnt; uint32_t* edge_timings; - uint32_t* reload_reg_buff; + uint32_t* reload_reg_buff; /* internal, but used by unit tests */ + DigitalSignalInternals* internals; } DigitalSignal; +typedef struct DigitalSequence DigitalSequence; + DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); void digital_signal_free(DigitalSignal* signal); +void digital_signal_add(DigitalSignal* signal, uint32_t ticks); + +void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level); + bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b); void digital_signal_prepare_arr(DigitalSignal* signal); @@ -34,6 +51,25 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); +DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio); + +void digital_sequence_free(DigitalSequence* sequence); + +void digital_sequence_set_signal( + DigitalSequence* sequence, + uint8_t signal_index, + DigitalSignal* signal); + +void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time); + +void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index); + +bool digital_sequence_send(DigitalSequence* sequence); + +void digital_sequence_clear(DigitalSequence* sequence); + +void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor); + #ifdef __cplusplus } #endif diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript new file mode 100644 index 000000000..f00851a20 --- /dev/null +++ b/lib/pulse_reader/SConscript @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/pulse_reader", + ], + SDK_HEADERS=[ + File("pulse_reader.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="pulse_reader") +libenv.ApplyLibFlags() + +libenv.AppendUnique( + CCFLAGS=[ + # Required for lib to be linkable with .faps + "-mword-relocations", + "-mlong-calls", + ], +) + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c new file mode 100644 index 000000000..74d99fe80 --- /dev/null +++ b/lib/pulse_reader/pulse_reader.c @@ -0,0 +1,233 @@ +#include "pulse_reader.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +struct PulseReader { + uint32_t* timer_buffer; + uint32_t* gpio_buffer; + uint32_t size; + uint32_t pos; + uint32_t timer_value; + uint32_t gpio_value; + uint32_t gpio_mask; + uint32_t unit_multiplier; + uint32_t unit_divider; + uint32_t bit_time; + uint32_t dma_channel; + const GpioPin* gpio; + GpioPull pull; + LL_DMA_InitTypeDef dma_config_timer; + LL_DMA_InitTypeDef dma_config_gpio; +}; + +#define GPIO_PIN_MAP(pin, prefix) \ + (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ + ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ + ((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \ + ((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \ + ((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \ + ((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \ + ((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \ + ((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \ + ((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \ + ((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \ + ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ + ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ + ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ + ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ + ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ + prefix##15) + +#define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE) + +PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { + PulseReader* signal = malloc(sizeof(PulseReader)); + signal->timer_buffer = malloc(size * sizeof(uint32_t)); + signal->gpio_buffer = malloc(size * sizeof(uint32_t)); + signal->dma_channel = LL_DMA_CHANNEL_4; + signal->gpio = gpio; + signal->pull = GpioPullNo; + signal->size = size; + signal->timer_value = 0; + signal->pos = 0; + + pulse_reader_set_timebase(signal, PulseReaderUnit64MHz); + pulse_reader_set_bittime(signal, 1); + + signal->dma_config_timer.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->CNT); + signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->timer_buffer; + signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_timer.PeriphRequest = + LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_timer.Priority = LL_DMA_PRIORITY_VERYHIGH; + + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_gpio.PeriphRequest = + LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + return signal; +} + +void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit) { + switch(unit) { + case PulseReaderUnit64MHz: + signal->unit_multiplier = 1; + signal->unit_divider = 1; + break; + case PulseReaderUnitPicosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1; + break; + case PulseReaderUnitNanosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000; + break; + case PulseReaderUnitMicrosecond: + signal->unit_multiplier = 15625; + signal->unit_divider = 1000000; + break; + } +} + +void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) { + signal->bit_time = bit_time; +} + +void pulse_reader_set_pull(PulseReader* signal, GpioPull pull) { + signal->pull = pull; +} + +void pulse_reader_free(PulseReader* signal) { + furi_assert(signal); + + free(signal->timer_buffer); + free(signal->gpio_buffer); + free(signal); +} + +uint32_t pulse_reader_samples(PulseReader* signal) { + uint32_t dma_pos = signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); + + return ((signal->pos + signal->size) - dma_pos) % signal->size; +} + +void pulse_reader_stop(PulseReader* signal) { + LL_DMA_DisableChannel(DMA1, signal->dma_channel); + LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); + LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); + LL_TIM_DisableCounter(TIM2); + furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog); +} + +void pulse_reader_start(PulseReader* signal) { + /* configure DMA to read from a timer peripheral */ + signal->dma_config_timer.NbData = signal->size; + + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->IDR); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer; + signal->dma_config_gpio.NbData = signal->size; + + /* start counter */ + LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetPrescaler(TIM2, 0); + LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); + + /* generator 0 gets fed by EXTI_LINEn */ + LL_DMAMUX_SetRequestSignalID( + NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); + /* trigger on rising edge of the interrupt */ + LL_DMAMUX_SetRequestGenPolarity(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING); + /* now enable request generation again */ + LL_DMAMUX_EnableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); + + /* we need the EXTI to be configured as interrupt generating line, but no ISR registered */ + furi_hal_gpio_init_ex( + signal->gpio, GpioModeInterruptRiseFall, signal->pull, GpioSpeedVeryHigh, GpioAltFnUnused); + + /* capture current timer */ + signal->pos = 0; + signal->timer_value = TIM2->CNT; + signal->gpio_mask = signal->gpio->pin; + signal->gpio_value = signal->gpio->port->IDR & signal->gpio_mask; + + /* now set up DMA with these settings */ + LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer); + LL_DMA_Init(DMA1, signal->dma_channel + 1, &signal->dma_config_gpio); + LL_DMA_EnableChannel(DMA1, signal->dma_channel); + LL_DMA_EnableChannel(DMA1, signal->dma_channel + 1); +} + +uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { + uint32_t start_time = DWT->CYCCNT; + uint32_t timeout_ticks = timeout_us * (F_TIM2 / 1000000); + + do { + /* get the DMA's next write position by reading "remaining length" register */ + uint32_t dma_pos = + signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel); + + /* the DMA has advanced in the ringbuffer */ + if(dma_pos != signal->pos) { + uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value; + uint32_t last_gpio_value = signal->gpio_value; + + signal->gpio_value = signal->gpio_buffer[signal->pos]; + + /* check if the GPIO really toggled. if not, we lost an edge :( */ + if(((last_gpio_value ^ signal->gpio_value) & signal->gpio_mask) != signal->gpio_mask) { + signal->gpio_value ^= signal->gpio_mask; + return PULSE_READER_LOST_EDGE; + } + signal->timer_value = signal->timer_buffer[signal->pos]; + + signal->pos++; + signal->pos %= signal->size; + + uint32_t delta_unit = 0; + + /* probably larger values, so choose a wider data type */ + if(signal->unit_divider > 1) { + delta_unit = + (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider); + } else { + delta_unit = delta * signal->unit_multiplier; + } + + /* if to be scaled to bit times, save a few instructions. should be faster */ + if(signal->bit_time > 1) { + return (delta_unit + signal->bit_time / 2) / signal->bit_time; + } + + return delta_unit; + } + + /* check for timeout */ + uint32_t elapsed = DWT->CYCCNT - start_time; + + if(elapsed > timeout_ticks) { + return PULSE_READER_NO_EDGE; + } + } while(true); +} diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h new file mode 100644 index 000000000..62c5f2fa4 --- /dev/null +++ b/lib/pulse_reader/pulse_reader.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PULSE_READER_NO_EDGE (0xFFFFFFFFUL) +#define PULSE_READER_LOST_EDGE (0xFFFFFFFEUL) +#define F_TIM2 (64000000UL) + +/** + * unit of the edge durations to return + */ +typedef enum { + PulseReaderUnit64MHz, + PulseReaderUnitPicosecond, + PulseReaderUnitNanosecond, + PulseReaderUnitMicrosecond, +} PulseReaderUnit; + +/* using an anonymous type */ +typedef struct PulseReader PulseReader; + +/** Allocate a PulseReader object + * + * Allocates memory for a ringbuffer and initalizes the object + * + * @param[in] gpio the GPIO to use. will get configured as input. + * @param[in] size number of edges to buffer + */ +PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size); + +/** Free a PulseReader object + * + * Frees all memory of the given object + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_free(PulseReader* signal); + +/** Start signal capturing + * + * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values. + * Ensure that interrupts are always enabled, as the used EXTI line is handled as one. + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_start(PulseReader* signal); + +/** Stop signal capturing + * + * Frees DMA1, TIM2 and DMAMUX_REQ_GEN_0 + * + * @param[in] signal previously allocated PulseReader object. + */ +void pulse_reader_stop(PulseReader* signal); + +/** Recevie a sample from ringbuffer + * + * Waits for the specified time until a new edge gets detected. + * If not configured otherwise, the pulse duration will be in picosecond resolution. + * If a bittime was configured, the return value will contain the properly rounded + * number of bit times measured. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] timeout_us time to wait for a signal [µs] + * + * @returns the scaled value of the pulse duration + */ +uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us); + +/** Get available samples + * + * Get the number of available samples in the ringbuffer + * + * @param[in] signal previously allocated PulseReader object. + * + * @returns the number of samples in buffer + */ +uint32_t pulse_reader_samples(PulseReader* signal); + +/** Set timebase + * + * Set the timebase to be used when returning pulse duration. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] unit PulseReaderUnit64MHz or PulseReaderUnitPicosecond + */ +void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit); + +/** Set bit time + * + * Set the number of timebase units per bit. + * When set, the pulse_reader_receive() will return an already rounded + * bit count value instead of the raw duration. + * + * Set to 1 to return duration again. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] bit_time + */ +void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time); + +/** Set GPIO pull direction + * + * Some GPIOs need pulldown, others don't. By default the + * pull direction is GpioPullNo. + * + * @param[in] signal previously allocated PulseReader object. + * @param[in] pull GPIO pull direction + */ +void pulse_reader_set_pull(PulseReader* signal, GpioPull pull); + +#ifdef __cplusplus +} +#endif From d5403a089cb8f364f18e656ae4e9d577495cb9ce Mon Sep 17 00:00:00 2001 From: Nathan Nye Date: Mon, 8 May 2023 21:45:59 -0400 Subject: [PATCH 156/216] Add Mfkey32 application (#2517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Mfkey32 application * Fine tune RAM requirements, use FZ notification service API * Fix PVS security warnings, fix issue with cracking keys on the FZ * Prefer on-device or Flipper mobile app (seamless) * Mfkey32: change app category to NFC * Mfkey32: set target to f7 only * Silence PVS false positives * Correct PVS codes Co-authored-by: あく --- applications/external/mfkey32/application.fam | 17 + .../external/mfkey32/images/mfkey.png | Bin 0 -> 9060 bytes applications/external/mfkey32/mfkey.png | Bin 0 -> 9060 bytes applications/external/mfkey32/mfkey32.c | 1349 +++++++++++++++++ .../nfc/scenes/nfc_scene_mfkey_complete.c | 4 +- 5 files changed, 1368 insertions(+), 2 deletions(-) create mode 100644 applications/external/mfkey32/application.fam create mode 100644 applications/external/mfkey32/images/mfkey.png create mode 100644 applications/external/mfkey32/mfkey.png create mode 100644 applications/external/mfkey32/mfkey32.c diff --git a/applications/external/mfkey32/application.fam b/applications/external/mfkey32/application.fam new file mode 100644 index 000000000..9a9cbf581 --- /dev/null +++ b/applications/external/mfkey32/application.fam @@ -0,0 +1,17 @@ +App( + appid="mfkey32", + name="Mfkey32", + apptype=FlipperAppType.EXTERNAL, + targets=["f7"], + entry_point="mfkey32_main", + requires=[ + "gui", + "storage", + ], + stack_size=1 * 1024, + fap_icon="mfkey.png", + fap_category="Nfc", + fap_author="noproto", + fap_icon_assets="images", + fap_weburl="https://github.com/noproto/FlipperMfkey", +) diff --git a/applications/external/mfkey32/images/mfkey.png b/applications/external/mfkey32/images/mfkey.png new file mode 100644 index 0000000000000000000000000000000000000000..52ab29efb92bf5aa7c790b8043d2d07a7e74704d GIT binary patch literal 9060 zcmeHLc|4SB`ya`gt&*%Y21OdPF9tD_coPmO>|@kR(yI zB1+a0Qo0o*glK}z+_2)bH zofwBpEttwGMFgchm(ef6MoJ!5%BERtYs?BBRG*a@G-?C$&T4 z>l-HDO-E)QRNbuTd}d~^O`ni%^(}aH_>BXK7S&h=H?U4t(jOEkSbeJ&2NVh9yho`S3uecDk^ zGsl~HI*z?%loB30T)tUQvKza5#=NTPPM2ij)d9)Tu{aUjQEKhPhK{((+>GuQWQCANmXV3iq%wW4RXAVlDYK~Py`b~rCH;a``1xuH zu;N0?^P;mU0ej<%U3fJNq~nBeSM+#DVEG=KGmTWRvURONsP6n@*xh~cVwgIKj z3H*{079-s?6d|p8_xKJejmM)o7v(+TwZsRye@fn|+K_5%tM;YyF|0*VzsqwnVif$0f^Ex-Ry>Y*2b$jwh1mA4y_dt(Yq0MWG!l zQD8=mzzecWIMJof`+j4ncC#46MW7_Y@;pt(`$k_;Y9X+}xSHAG>nrL^1QOn69=}nf^by)#38K@bPdb^ja zU4DFmb{$aOL^>`};g;}J=)fHL#=MT)TJd9hx2=C0qVjrI{H5F=V`R4>T4~|J55^K# zS~`h#ZXrW9`^%)O>ejj3*H>g?68D|(PPwcQ13D={ih9{HSlT!M3#iNuo+5}TPZ6%S z1--2Goa++35v-@off(1(xJp-~B4zJ3su|iAJ{LgDX88#ZEAB5lUtz6!!#O0U=$F3m zv6X3sC3}vGt|79Wo}go6A*!1nBurDn$X4}LilvvVc7-XIrkgrRIUA_esN>bC>l^$Y zjYA9fMrqHQol_WSNUUUI)=L8eu=6Nf-dK+QQ)&Z&uE(U>BWb!n=D(J?HU-#dQJJX zQu*N9H_!85=c-FA-YtXGEVh=i+;`WY5fp`8_l6a$G~>`3tCEB{^`-&AACDYR@!K{u zjg8$?#c7B2p2|XY1f4r`-AcYl$atk1-lpfhIKiScyTj|?^qGpRif%i2D=SW}PfzL1 zpy}PU%7p>f4!vH4&&VVfjRr);89vyhe431X5#8&g*%oXsZ51XVdqH5uG41383hHFc zs%*+dzX^TuRqZNAcU+bDfD*rcw6|ErLBeZ;Q(?9cS<1i=Eg2nNLRBj1&_8c}&V5nN z;nT|T%7RCmowlDR9L&mYGilr@IN+ST)m_=_A~n@L#ZTaMgWOEaB4yo%j-!wT=wEnJerb6OScXPK^54z&?-3mEo zEnU70zXSzTYpS!^n!9(8-3wyR}`3UTtl(ntI zh^q9XW=-f>`eK2L@kG)UwxV#F%As)BL(sH|w;o4ow~0{n4#7jm=YDQjGI8y%$l$i@<1+#wt@pThrQSJ8WWeT=ejysE-J(2vPP$7AA z7t#PjEQ_{4@noYyVd_GvOwtD*)Qn(eXC?U)^nCzjFnP9UHc_}g)lPq+Mnkr0CcSV} zu3azNGwDMnvE!;~w&D7FF_-QHM!pi_&Gc3Ti6}y^Z1Vc0&_K*fLl9}vm~85jbk4m* zb9VJ(HI=lV#2f9Pg-_MH@>mB-w357%XQeEQTnjhNNl66U4;{wXoKqbW^CQ>?=l~hVsW)}qN)C|duida%|Evc4^S=B*=YjEOwwGID8a0gQmld8Eu5TMsd+x5HVmZ@w ziI^~u4Lz$#vKtdz#54z3Np~#FUvtp96BhGO25GID*R$?%yKHD+#{BK08#bGmOH3Yn zkh!^Pb8YVCrcS?mM=~D9C1&cpuiwslI^zUeDCg#ej>}bU{P7*p%hlNIbCzOdb;6qx z(P4~R$D|nlS{smP8fWymUw51TaqS)Zq(yFJNOt(+-^v^96hOPRk!b6ZtIS4qU)lN? z7i4y~$q0U0@tV@ZB_8g_b3H_!l*jzY$ZUGnz*G?x)9`|;r$RQDBw7TYJ*m=(Jex*| zn`0{Y79OPS@FMKIZv%panjC4kcvUmeg_0O=+~w65R+c%cZ8QVd%o*HyY@hV8(XPDx zWWuAV`QXvuM`oXRJ`WB)7S)PL6TOu!W#sEd5)asGMz&0^-*G-)^>Qyr$)zXP%6zz2 zWMYdwtn~Fc17%$a0|e*N+-VmBd}yIc6#sL z6nd%Q;m6_|q)Eu4jYLE`D|zrv)?E8NjVbjE3yY5;oy6Fx#>uy~I4YyJLh^&o!cpjg z_{1uo6Rd}?pDnD9n@C|zPnm6Gr<&%tHRs%CcNDa>9XKplo@V(XN~~!8AyQX%$~5B* zQaJFj+)=8kivtkr)%zz z$d^?n9!pgoc;%QfF;Ll@le@UDjQ5I?n9)RjMpi7KzaLy5%X6Ge3pnqbq5t4bXj&_5 zc%iwxG1>jxifW7vDHiQ3@#zD~>Dsdfc(;7E`Qz4g7a|T~1}`6ybGf&wHwE*`liQ6l4oAm{WMG@s9wP+7(TzUQ`oY1 zvtZp-d#RbTTH9TcZ=qg#T0CM~eoE08n@kESNza?K{MeWLRXCzngUV;jrfu)wWC)8R zMix%^#&s^7AIm)_r}R{rtfpQMy5`szWQ0K4|?)7vFus?R867(PxIA#s%=kCR7qxUnwFJa z_crVOZTvl=J!;E+eIb>DAg_G37nmpB(o6q6+QQax)ltiObZ_pqeKUKZ~?StM+0=L_bfEmCs3R=3!k-TGmNa=AFEK*lTDQN@z=DPof(`B+@; z&>r8nrB437e%)Pl4l*k@f{S&mkLlRHsA8Tc#f#|74cCr*u9|Z-ERf4!lqU$BW@W}Y z*<0rCZn&)-Hfjosf$N~|pGwKY>yM9T-6))Z=-;oNY=3Qwk`oMrOl?J3W(GwDg>+)^ zlWUJS?Q@K6k2STr0iIIpNh8$yJ*e9Hw)J?1W$W4_M;lyMX+vAzT`+rzkOu0t}W}?MSzI9alzUxKIQF*!2m0}Rt)Ln+Fv5;%yc}`{>!H@53ANr)h(fVmi z_z9|j#{T1bw}05Ukaaoj?3seiLb-H}fjx140v|e$0uJ)=W^oBY29PCQ0&veChC#qf5Z(a;h?A8Kn8@bP!Dt<{4jf7f zVg?`~+r+{892$dQYi#m`0(dfj?C0@(2{2e-V4zMQN{7wygducwbzyKM42gsS2q-t0 z#iIm4SzI+f#WII6olE5~eR)ha3(V)Fc(DC>1`r4!2Y(?4q*PK6F!;p)|9Od?%cH@_ zzylhH2LQm3a5x?cM?#Uhu1NZ5H=S7J+=if+)T)gbp0$e_llI8DpOvzR@Uv>Ct z^kn+@E@|-5-y><%uQ*?Sj`tFVMupM6={|rXT!0zz8$ACr%vX)y#KV{T&JiAy@lW7< z$?xERcYjR&YkHSlUz!GjF`Meo_mOOD0O5y6ps}e;8e!=cL1SR4SQ-{e#nZ7+G!{#T z;&H&mgHFeI;NU0(4vqSbip=8jC@dBE)-2iVWD^i9S%hz=@bl& zip8Pm=p`!tv=NMK$OaIk4*c7QjW>nIU~_y7AeKy)f6zC9J=2G7$D{C*hQQ*`SUeUe zTr?hw`4Zg{pCg^a1=a+g69Lyj;Fr{CRDub>NC9e-=|l0P!+cquO9K8Z5^R`3bZ;kP zfSt9hidgpMo6!09LjHsjfHVM8Lg6n$z^5g~rEz|Fd;9Z;9av1jDDs=g>6^>|f&&78 z!(j;i^&72}BN^!lN4lKY$w!bO{8IUbHqh;5erA+ zD0m<+49i&~|U;5&I(gYa%w~@b; z-@nuKce?&k2L2NG@9O$HU4JP9e+m3|b^Y7YCI0P`8Jz{Zkpu!C#G)SBy#hX_iTRp2 zb3ve0YxzF`(CIVsz@P|^Y()|o5m1m**Icz`(|KTsNH#XIm+wqSB#VRKqJnFuKD${< z+lqOd=k9Vf5imS?kD?ArPBsfDKavwMx2f2_Do?p$?=KNlw!ZwhcI`XYiHy&no*dYF T2_+RDfDS|^SsNGcaF6&O#taN} literal 0 HcmV?d00001 diff --git a/applications/external/mfkey32/mfkey.png b/applications/external/mfkey32/mfkey.png new file mode 100644 index 0000000000000000000000000000000000000000..52ab29efb92bf5aa7c790b8043d2d07a7e74704d GIT binary patch literal 9060 zcmeHLc|4SB`ya`gt&*%Y21OdPF9tD_coPmO>|@kR(yI zB1+a0Qo0o*glK}z+_2)bH zofwBpEttwGMFgchm(ef6MoJ!5%BERtYs?BBRG*a@G-?C$&T4 z>l-HDO-E)QRNbuTd}d~^O`ni%^(}aH_>BXK7S&h=H?U4t(jOEkSbeJ&2NVh9yho`S3uecDk^ zGsl~HI*z?%loB30T)tUQvKza5#=NTPPM2ij)d9)Tu{aUjQEKhPhK{((+>GuQWQCANmXV3iq%wW4RXAVlDYK~Py`b~rCH;a``1xuH zu;N0?^P;mU0ej<%U3fJNq~nBeSM+#DVEG=KGmTWRvURONsP6n@*xh~cVwgIKj z3H*{079-s?6d|p8_xKJejmM)o7v(+TwZsRye@fn|+K_5%tM;YyF|0*VzsqwnVif$0f^Ex-Ry>Y*2b$jwh1mA4y_dt(Yq0MWG!l zQD8=mzzecWIMJof`+j4ncC#46MW7_Y@;pt(`$k_;Y9X+}xSHAG>nrL^1QOn69=}nf^by)#38K@bPdb^ja zU4DFmb{$aOL^>`};g;}J=)fHL#=MT)TJd9hx2=C0qVjrI{H5F=V`R4>T4~|J55^K# zS~`h#ZXrW9`^%)O>ejj3*H>g?68D|(PPwcQ13D={ih9{HSlT!M3#iNuo+5}TPZ6%S z1--2Goa++35v-@off(1(xJp-~B4zJ3su|iAJ{LgDX88#ZEAB5lUtz6!!#O0U=$F3m zv6X3sC3}vGt|79Wo}go6A*!1nBurDn$X4}LilvvVc7-XIrkgrRIUA_esN>bC>l^$Y zjYA9fMrqHQol_WSNUUUI)=L8eu=6Nf-dK+QQ)&Z&uE(U>BWb!n=D(J?HU-#dQJJX zQu*N9H_!85=c-FA-YtXGEVh=i+;`WY5fp`8_l6a$G~>`3tCEB{^`-&AACDYR@!K{u zjg8$?#c7B2p2|XY1f4r`-AcYl$atk1-lpfhIKiScyTj|?^qGpRif%i2D=SW}PfzL1 zpy}PU%7p>f4!vH4&&VVfjRr);89vyhe431X5#8&g*%oXsZ51XVdqH5uG41383hHFc zs%*+dzX^TuRqZNAcU+bDfD*rcw6|ErLBeZ;Q(?9cS<1i=Eg2nNLRBj1&_8c}&V5nN z;nT|T%7RCmowlDR9L&mYGilr@IN+ST)m_=_A~n@L#ZTaMgWOEaB4yo%j-!wT=wEnJerb6OScXPK^54z&?-3mEo zEnU70zXSzTYpS!^n!9(8-3wyR}`3UTtl(ntI zh^q9XW=-f>`eK2L@kG)UwxV#F%As)BL(sH|w;o4ow~0{n4#7jm=YDQjGI8y%$l$i@<1+#wt@pThrQSJ8WWeT=ejysE-J(2vPP$7AA z7t#PjEQ_{4@noYyVd_GvOwtD*)Qn(eXC?U)^nCzjFnP9UHc_}g)lPq+Mnkr0CcSV} zu3azNGwDMnvE!;~w&D7FF_-QHM!pi_&Gc3Ti6}y^Z1Vc0&_K*fLl9}vm~85jbk4m* zb9VJ(HI=lV#2f9Pg-_MH@>mB-w357%XQeEQTnjhNNl66U4;{wXoKqbW^CQ>?=l~hVsW)}qN)C|duida%|Evc4^S=B*=YjEOwwGID8a0gQmld8Eu5TMsd+x5HVmZ@w ziI^~u4Lz$#vKtdz#54z3Np~#FUvtp96BhGO25GID*R$?%yKHD+#{BK08#bGmOH3Yn zkh!^Pb8YVCrcS?mM=~D9C1&cpuiwslI^zUeDCg#ej>}bU{P7*p%hlNIbCzOdb;6qx z(P4~R$D|nlS{smP8fWymUw51TaqS)Zq(yFJNOt(+-^v^96hOPRk!b6ZtIS4qU)lN? z7i4y~$q0U0@tV@ZB_8g_b3H_!l*jzY$ZUGnz*G?x)9`|;r$RQDBw7TYJ*m=(Jex*| zn`0{Y79OPS@FMKIZv%panjC4kcvUmeg_0O=+~w65R+c%cZ8QVd%o*HyY@hV8(XPDx zWWuAV`QXvuM`oXRJ`WB)7S)PL6TOu!W#sEd5)asGMz&0^-*G-)^>Qyr$)zXP%6zz2 zWMYdwtn~Fc17%$a0|e*N+-VmBd}yIc6#sL z6nd%Q;m6_|q)Eu4jYLE`D|zrv)?E8NjVbjE3yY5;oy6Fx#>uy~I4YyJLh^&o!cpjg z_{1uo6Rd}?pDnD9n@C|zPnm6Gr<&%tHRs%CcNDa>9XKplo@V(XN~~!8AyQX%$~5B* zQaJFj+)=8kivtkr)%zz z$d^?n9!pgoc;%QfF;Ll@le@UDjQ5I?n9)RjMpi7KzaLy5%X6Ge3pnqbq5t4bXj&_5 zc%iwxG1>jxifW7vDHiQ3@#zD~>Dsdfc(;7E`Qz4g7a|T~1}`6ybGf&wHwE*`liQ6l4oAm{WMG@s9wP+7(TzUQ`oY1 zvtZp-d#RbTTH9TcZ=qg#T0CM~eoE08n@kESNza?K{MeWLRXCzngUV;jrfu)wWC)8R zMix%^#&s^7AIm)_r}R{rtfpQMy5`szWQ0K4|?)7vFus?R867(PxIA#s%=kCR7qxUnwFJa z_crVOZTvl=J!;E+eIb>DAg_G37nmpB(o6q6+QQax)ltiObZ_pqeKUKZ~?StM+0=L_bfEmCs3R=3!k-TGmNa=AFEK*lTDQN@z=DPof(`B+@; z&>r8nrB437e%)Pl4l*k@f{S&mkLlRHsA8Tc#f#|74cCr*u9|Z-ERf4!lqU$BW@W}Y z*<0rCZn&)-Hfjosf$N~|pGwKY>yM9T-6))Z=-;oNY=3Qwk`oMrOl?J3W(GwDg>+)^ zlWUJS?Q@K6k2STr0iIIpNh8$yJ*e9Hw)J?1W$W4_M;lyMX+vAzT`+rzkOu0t}W}?MSzI9alzUxKIQF*!2m0}Rt)Ln+Fv5;%yc}`{>!H@53ANr)h(fVmi z_z9|j#{T1bw}05Ukaaoj?3seiLb-H}fjx140v|e$0uJ)=W^oBY29PCQ0&veChC#qf5Z(a;h?A8Kn8@bP!Dt<{4jf7f zVg?`~+r+{892$dQYi#m`0(dfj?C0@(2{2e-V4zMQN{7wygducwbzyKM42gsS2q-t0 z#iIm4SzI+f#WII6olE5~eR)ha3(V)Fc(DC>1`r4!2Y(?4q*PK6F!;p)|9Od?%cH@_ zzylhH2LQm3a5x?cM?#Uhu1NZ5H=S7J+=if+)T)gbp0$e_llI8DpOvzR@Uv>Ct z^kn+@E@|-5-y><%uQ*?Sj`tFVMupM6={|rXT!0zz8$ACr%vX)y#KV{T&JiAy@lW7< z$?xERcYjR&YkHSlUz!GjF`Meo_mOOD0O5y6ps}e;8e!=cL1SR4SQ-{e#nZ7+G!{#T z;&H&mgHFeI;NU0(4vqSbip=8jC@dBE)-2iVWD^i9S%hz=@bl& zip8Pm=p`!tv=NMK$OaIk4*c7QjW>nIU~_y7AeKy)f6zC9J=2G7$D{C*hQQ*`SUeUe zTr?hw`4Zg{pCg^a1=a+g69Lyj;Fr{CRDub>NC9e-=|l0P!+cquO9K8Z5^R`3bZ;kP zfSt9hidgpMo6!09LjHsjfHVM8Lg6n$z^5g~rEz|Fd;9Z;9av1jDDs=g>6^>|f&&78 z!(j;i^&72}BN^!lN4lKY$w!bO{8IUbHqh;5erA+ zD0m<+49i&~|U;5&I(gYa%w~@b; z-@nuKce?&k2L2NG@9O$HU4JP9e+m3|b^Y7YCI0P`8Jz{Zkpu!C#G)SBy#hX_iTRp2 zb3ve0YxzF`(CIVsz@P|^Y()|o5m1m**Icz`(|KTsNH#XIm+wqSB#VRKqJnFuKD${< z+lqOd=k9Vf5imS?kD?ArPBsfDKavwMx2f2_Do?p$?=KNlw!ZwhcI`XYiHy&no*dYF T2_+RDfDS|^SsNGcaF6&O#taN} literal 0 HcmV?d00001 diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c new file mode 100644 index 000000000..2934d837a --- /dev/null +++ b/applications/external/mfkey32/mfkey32.c @@ -0,0 +1,1349 @@ +#pragma GCC optimize("O3") +#pragma GCC optimize("-funroll-all-loops") + +// TODO: Add keys to top of the user dictionary, not the bottom +// TODO: More efficient dictionary bruteforce by scanning through hardcoded very common keys and previously found dictionary keys first? +// (a cache for napi_key_already_found_for_nonce) + +#include +#include +#include "time.h" +#include +#include +#include +#include +#include "mfkey32_icons.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") +#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") +#define MF_CLASSIC_NONCE_PATH EXT_PATH("nfc/.mfkey32.log") +#define TAG "Mfkey32" +#define NFC_MF_CLASSIC_KEY_LEN (13) + +#define MIN_RAM 115632 +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) +#define BIT(x, n) ((x) >> (n)&1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define SWAPENDIAN(x) \ + (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) //-V1003 +//#define SIZEOF(arr) sizeof(arr) / sizeof(*arr) + +static int eta_round_time = 56; +static int eta_total_time = 900; +// MSB_LIMIT: Chunk size (out of 256) +static int MSB_LIMIT = 16; + +struct Crypto1State { + uint32_t odd, even; +}; +struct Crypto1Params { + uint64_t key; + uint32_t nr0_enc, uid_xor_nt0, uid_xor_nt1, nr1_enc, p64b, ar1_enc; +}; +struct Msb { + int tail; + uint32_t states[768]; +}; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} PluginEvent; + +typedef enum { + MissingNonces, + ZeroNonces, +} MfkeyError; + +typedef enum { + Ready, + Initializing, + DictionaryAttack, + MfkeyAttack, + Complete, + Error, + Help, +} MfkeyState; + +// TODO: Can we eliminate any of the members of this struct? +typedef struct { + FuriMutex* mutex; + MfkeyError err; + MfkeyState mfkey_state; + int cracked; + int unique_cracked; + int num_completed; + int total; + int dict_count; + int search; + int eta_timestamp; + int eta_total; + int eta_round; + bool is_thread_running; + bool close_thread_please; + FuriThread* mfkeythread; +} ProgramState; + +// TODO: Merge this with Crypto1Params? +typedef struct { + uint32_t uid; // serial number + uint32_t nt0; // tag challenge first + uint32_t nt1; // tag challenge second + uint32_t nr0_enc; // first encrypted reader challenge + uint32_t ar0_enc; // first encrypted reader response + uint32_t nr1_enc; // second encrypted reader challenge + uint32_t ar1_enc; // second encrypted reader response +} MfClassicNonce; + +typedef struct { + Stream* stream; + uint32_t total_nonces; + MfClassicNonce* remaining_nonce_array; + size_t remaining_nonces; +} MfClassicNonceArray; + +struct MfClassicDict { + Stream* stream; + uint32_t total_keys; +}; + +static const uint8_t table[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, + 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, + 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, + 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, + 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, + 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; +static const uint8_t lookup1[256] = { + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, + 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24}; +static const uint8_t lookup2[256] = { + 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, + 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, + 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, + 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, + 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, + 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, + 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, + 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, + 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; + +uint32_t prng_successor(uint32_t x, uint32_t n) { + SWAPENDIAN(x); + while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + return SWAPENDIAN(x); +} + +static inline int filter(uint32_t const x) { + uint32_t f; + f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; + f |= 0x0d938 >> (x >> 16 & 0xf) & 1; + return BIT(0xEC57E80A, f); +} + +static inline uint8_t evenparity32(uint32_t x) { + if((table[x & 0xff] + table[(x >> 8) & 0xff] + table[(x >> 16) & 0xff] + table[x >> 24]) % 2 == + 0) { + return 0; + } else { + return 1; + } + //return ((table[x & 0xff] + table[(x >> 8) & 0xff] + table[(x >> 16) & 0xff] + table[x >> 24]) % 2) & 0xFF; +} + +static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) { + int p = data[item] >> 25; + p = p << 1 | evenparity32(data[item] & mask1); + p = p << 1 | evenparity32(data[item] & mask2); + data[item] = p << 24 | (data[item] & 0xffffff); +} + +void crypto1_get_lfsr(struct Crypto1State* state, uint64_t* lfsr) { + int i; + for(*lfsr = 0, i = 23; i >= 0; --i) { + *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); + *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); + } +} + +static inline uint32_t crypt_word(struct Crypto1State* s) { + // "in" and "x" are always 0 (last iteration) + uint32_t res_ret = 0; + uint32_t feedin, t; + for(int i = 0; i <= 31; i++) { + res_ret |= (filter(s->odd) << (24 ^ i)); //-V629 + feedin = LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return res_ret; +} + +static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 0; i <= 31; i++) { + next_in = BEBIT(in, i); + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return; +} + +static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 31; i >= 0; i--) { + next_in = BEBIT(in, i); + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= s->even & 1; + feedin ^= LF_POLY_EVEN & (s->even >>= 1); + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even |= (evenparity32(feedin)) << 23; + } + return; +} + +int key_already_found_for_nonce( + uint64_t* keyarray, + int keyarray_size, + uint32_t uid_xor_nt1, + uint32_t nr1_enc, + uint32_t p64b, + uint32_t ar1_enc) { + for(int k = 0; k < keyarray_size; k++) { + struct Crypto1State temp = {0, 0}; + + for(int i = 0; i < 24; i++) { + (&temp)->odd |= (BIT(keyarray[k], 2 * i + 1) << (i ^ 3)); + (&temp)->even |= (BIT(keyarray[k], 2 * i) << (i ^ 3)); + } + + crypt_word_noret(&temp, uid_xor_nt1, 0); + crypt_word_noret(&temp, nr1_enc, 1); + + if(ar1_enc == (crypt_word(&temp) ^ p64b)) { + return 1; + } + } + return 0; +} + +int check_state(struct Crypto1State* t, struct Crypto1Params* p) { + if(!(t->odd | t->even)) return 0; + rollback_word_noret(t, 0, 0); + rollback_word_noret(t, p->nr0_enc, 1); + rollback_word_noret(t, p->uid_xor_nt0, 0); + struct Crypto1State temp = {t->odd, t->even}; + crypt_word_noret(t, p->uid_xor_nt1, 0); + crypt_word_noret(t, p->nr1_enc, 1); + if(p->ar1_enc == (crypt_word(t) ^ p->p64b)) { + crypto1_get_lfsr(&temp, &(p->key)); + return 1; + } + return 0; +} + +static inline int state_loop(unsigned int* states_buffer, int xks, int m1, int m2) { + int states_tail = 0; + int round = 0, s = 0, xks_bit = 0; + + for(round = 1; round <= 12; round++) { + xks_bit = BIT(xks, round); + + for(s = 0; s <= states_tail; s++) { + states_buffer[s] <<= 1; + + if((filter(states_buffer[s]) ^ filter(states_buffer[s] | 1)) != 0) { + states_buffer[s] |= filter(states_buffer[s]) ^ xks_bit; + if(round > 4) { + update_contribution(states_buffer, s, m1, m2); + } + } else if(filter(states_buffer[s]) == xks_bit) { + // TODO: Refactor + if(round > 4) { + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s + 1] = states_buffer[s] | 1; + update_contribution(states_buffer, s, m1, m2); + s++; + update_contribution(states_buffer, s, m1, m2); + } else { + states_buffer[++states_tail] = states_buffer[++s]; + states_buffer[s] = states_buffer[s - 1] | 1; + } + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } + + return states_tail; +} + +int binsearch(unsigned int data[], int start, int stop) { + int mid, val = data[stop] & 0xff000000; + while(start != stop) { + mid = (stop - start) >> 1; + if((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000)) + stop = start + mid; + else + start += mid + 1; + } + return start; +} +void quicksort(unsigned int array[], int low, int high) { + //if (SIZEOF(array) == 0) + // return; + if(low >= high) return; + int middle = low + (high - low) / 2; + unsigned int pivot = array[middle]; + int i = low, j = high; + while(i <= j) { + while(array[i] < pivot) { + i++; + } + while(array[j] > pivot) { + j--; + } + if(i <= j) { // swap + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } + } + if(low < j) { + quicksort(array, low, j); + } + if(high > i) { + quicksort(array, i, high); + } +} +int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2) { + for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { + if((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) { + data[tbl] |= filter(data[tbl]) ^ bit; + update_contribution(data, tbl, m1, m2); + } else if(filter(data[tbl]) == bit) { + data[++end] = data[tbl + 1]; + data[tbl + 1] = data[tbl] | 1; + update_contribution(data, tbl, m1, m2); + tbl++; + update_contribution(data, tbl, m1, m2); + } else { + data[tbl--] = data[end--]; + } + } + return end; +} + +int old_recover( + unsigned int odd[], + int o_head, + int o_tail, + int oks, + unsigned int even[], + int e_head, + int e_tail, + int eks, + int rem, + int s, + struct Crypto1Params* p, + int first_run) { + int o, e, i; + if(rem == -1) { + for(e = e_head; e <= e_tail; ++e) { + even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN); + for(o = o_head; o <= o_tail; ++o, ++s) { + struct Crypto1State temp = {0, 0}; + temp.even = odd[o]; + temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD); + if(check_state(&temp, p)) { + return -1; + } + } + } + return s; + } + if(first_run == 0) { + for(i = 0; (i < 4) && (rem-- != 0); i++) { + oks >>= 1; + eks >>= 1; + o_tail = extend_table( + odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1); + if(o_head > o_tail) return s; + e_tail = + extend_table(even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1); + if(e_head > e_tail) return s; + } + } + first_run = 0; + quicksort(odd, o_head, o_tail); + quicksort(even, e_head, e_tail); + while(o_tail >= o_head && e_tail >= e_head) { + if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) { + o_tail = binsearch(odd, o_head, o = o_tail); + e_tail = binsearch(even, e_head, e = e_tail); + s = old_recover(odd, o_tail--, o, oks, even, e_tail--, e, eks, rem, s, p, first_run); + if(s == -1) { + break; + } + } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) { + o_tail = binsearch(odd, o_head, o_tail) - 1; + } else { + e_tail = binsearch(even, e_head, e_tail) - 1; + } + } + return s; +} + +static inline int sync_state(ProgramState* program_state) { + int ts = furi_hal_rtc_get_timestamp(); + program_state->eta_round = program_state->eta_round - (ts - program_state->eta_timestamp); + program_state->eta_total = program_state->eta_total - (ts - program_state->eta_timestamp); + program_state->eta_timestamp = ts; + if(program_state->close_thread_please) { + return 1; + } + return 0; +} + +int calculate_msb_tables( + int oks, + int eks, + int msb_round, + struct Crypto1Params* p, + unsigned int* states_buffer, + struct Msb* odd_msbs, + struct Msb* even_msbs, + unsigned int* temp_states_odd, + unsigned int* temp_states_even, + ProgramState* program_state) { + //FURI_LOG_I(TAG, "MSB GO %i", msb_iter); // DEBUG + unsigned int msb_head = (MSB_LIMIT * msb_round); // msb_iter ranges from 0 to (256/MSB_LIMIT)-1 + unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); + int states_tail = 0, tail = 0; + int i = 0, j = 0, semi_state = 0, found = 0; + unsigned int msb = 0; + // TODO: Why is this necessary? + memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + + for(semi_state = 1 << 20; semi_state >= 0; semi_state--) { + if(semi_state % 32768 == 0) { + if(sync_state(program_state) == 1) { + return 0; + } + } + + if(filter(semi_state) == (oks & 1)) { //-V547 + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1); + + for(i = states_tail; i >= 0; i--) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + found = 0; + for(j = 0; j < odd_msbs[msb - msb_head].tail - 1; j++) { + if(odd_msbs[msb - msb_head].states[j] == states_buffer[i]) { + found = 1; + break; + } + } + + if(!found) { + tail = odd_msbs[msb - msb_head].tail++; + odd_msbs[msb - msb_head].states[tail] = states_buffer[i]; + } + } + } + } + + if(filter(semi_state) == (eks & 1)) { //-V547 + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2); + + for(i = 0; i <= states_tail; i++) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + found = 0; + + for(j = 0; j < even_msbs[msb - msb_head].tail; j++) { + if(even_msbs[msb - msb_head].states[j] == states_buffer[i]) { + found = 1; + break; + } + } + + if(!found) { + tail = even_msbs[msb - msb_head].tail++; + even_msbs[msb - msb_head].states[tail] = states_buffer[i]; + } + } + } + } + } + + oks >>= 12; + eks >>= 12; + + for(i = 0; i < MSB_LIMIT; i++) { + if(sync_state(program_state) == 1) { + return 0; + } + // TODO: Why is this necessary? + memset(temp_states_even, 0, sizeof(unsigned int) * (1280)); + memset(temp_states_odd, 0, sizeof(unsigned int) * (1280)); + memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int)); + memcpy(temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int)); + int res = old_recover( + temp_states_odd, + 0, + odd_msbs[i].tail, + oks, + temp_states_even, + 0, + even_msbs[i].tail, + eks, + 3, + 0, + p, + 1); + if(res == -1) { + return 1; + } + //odd_msbs[i].tail = 0; + //even_msbs[i].tail = 0; + } + + return 0; +} + +bool recover(struct Crypto1Params* p, int ks2, ProgramState* program_state) { + bool found = false; + unsigned int* states_buffer = malloc(sizeof(unsigned int) * (2 << 9)); + struct Msb* odd_msbs = (struct Msb*)malloc(MSB_LIMIT * sizeof(struct Msb)); + struct Msb* even_msbs = (struct Msb*)malloc(MSB_LIMIT * sizeof(struct Msb)); + unsigned int* temp_states_odd = malloc(sizeof(unsigned int) * (1280)); + unsigned int* temp_states_even = malloc(sizeof(unsigned int) * (1280)); + int oks = 0, eks = 0; + int i = 0, msb = 0; + for(i = 31; i >= 0; i -= 2) { + oks = oks << 1 | BEBIT(ks2, i); + } + for(i = 30; i >= 0; i -= 2) { + eks = eks << 1 | BEBIT(ks2, i); + } + int bench_start = furi_hal_rtc_get_timestamp(); + program_state->eta_total = eta_total_time; + program_state->eta_timestamp = bench_start; + for(msb = 0; msb <= ((256 / MSB_LIMIT) - 1); msb++) { + program_state->search = msb; + program_state->eta_round = eta_round_time; + program_state->eta_total = eta_total_time - (eta_round_time * msb); + if(calculate_msb_tables( + oks, + eks, + msb, + p, + states_buffer, + odd_msbs, + even_msbs, + temp_states_odd, + temp_states_even, + program_state)) { + int bench_stop = furi_hal_rtc_get_timestamp(); + FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start); + found = true; + break; + } + if(program_state->close_thread_please) { + break; + } + } + free(states_buffer); + free(odd_msbs); + free(even_msbs); + free(temp_states_odd); + free(temp_states_even); + return found; +} + +bool napi_mf_classic_dict_check_presence(MfClassicDictType dict_type) { + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool dict_present = false; + if(dict_type == MfClassicDictTypeSystem) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK; + } else if(dict_type == MfClassicDictTypeUser) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK; + } + + furi_record_close(RECORD_STORAGE); + + return dict_present; +} + +MfClassicDict* napi_mf_classic_dict_alloc(MfClassicDictType dict_type) { + MfClassicDict* dict = malloc(sizeof(MfClassicDict)); + Storage* storage = furi_record_open(RECORD_STORAGE); + dict->stream = buffered_file_stream_alloc(storage); + furi_record_close(RECORD_STORAGE); + + bool dict_loaded = false; + do { + if(dict_type == MfClassicDictTypeSystem) { + if(!buffered_file_stream_open( + dict->stream, + MF_CLASSIC_DICT_FLIPPER_PATH, + FSAM_READ_WRITE, + FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(dict->stream); + break; + } + } else if(dict_type == MfClassicDictTypeUser) { + if(!buffered_file_stream_open( + dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { + buffered_file_stream_close(dict->stream); + break; + } + } + + // Check for newline ending + if(!stream_eof(dict->stream)) { + if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break; + uint8_t last_char = 0; + if(stream_read(dict->stream, &last_char, 1) != 1) break; + if(last_char != '\n') { + FURI_LOG_D(TAG, "Adding new line ending"); + if(stream_write_char(dict->stream, '\n') != 1) break; + } + if(!stream_rewind(dict->stream)) break; + } + + // Read total amount of keys + FuriString* next_line; + next_line = furi_string_alloc(); + while(true) { + if(!stream_read_line(dict->stream, next_line)) { + FURI_LOG_T(TAG, "No keys left in dict"); + break; + } + FURI_LOG_T( + TAG, + "Read line: %s, len: %zu", + furi_string_get_cstr(next_line), + furi_string_size(next_line)); + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + dict->total_keys++; + } + furi_string_free(next_line); + stream_rewind(dict->stream); + + dict_loaded = true; + FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys); + } while(false); + + if(!dict_loaded) { + buffered_file_stream_close(dict->stream); + free(dict); + dict = NULL; + } + + return dict; +} + +bool napi_mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + FURI_LOG_I(TAG, "Saving key: %s", furi_string_get_cstr(key)); + + furi_string_cat_printf(key, "\n"); + + bool key_added = false; + do { + if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break; + if(!stream_insert_string(dict->stream, key)) break; + dict->total_keys++; + key_added = true; + } while(false); + + furi_string_left(key, 12); + return key_added; +} + +void napi_mf_classic_dict_free(MfClassicDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + buffered_file_stream_close(dict->stream); + stream_free(dict->stream); + free(dict); +} + +static void napi_mf_classic_dict_int_to_str(uint8_t* key_int, FuriString* key_str) { + furi_string_reset(key_str); + for(size_t i = 0; i < 6; i++) { + furi_string_cat_printf(key_str, "%02X", key_int[i]); + } +} + +static void napi_mf_classic_dict_str_to_int(FuriString* key_str, uint64_t* key_int) { + uint8_t key_byte_tmp; + + *key_int = 0ULL; + for(uint8_t i = 0; i < 12; i += 2) { + args_char_to_hex( + furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp); + *key_int |= (uint64_t)key_byte_tmp << (8 * (5 - i / 2)); + } +} + +uint32_t napi_mf_classic_dict_get_total_keys(MfClassicDict* dict) { + furi_assert(dict); + + return dict->total_keys; +} + +bool napi_mf_classic_dict_rewind(MfClassicDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + return stream_rewind(dict->stream); +} + +bool napi_mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + + bool key_read = false; + furi_string_reset(key); + while(!key_read) { + if(!stream_read_line(dict->stream, key)) break; + if(furi_string_get_char(key, 0) == '#') continue; + if(furi_string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue; + furi_string_left(key, 12); + key_read = true; + } + + return key_read; +} + +bool napi_mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* temp_key; + temp_key = furi_string_alloc(); + bool key_read = napi_mf_classic_dict_get_next_key_str(dict, temp_key); + if(key_read) { + napi_mf_classic_dict_str_to_int(temp_key, key); + } + furi_string_free(temp_key); + return key_read; +} + +bool napi_mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* next_line; + next_line = furi_string_alloc(); + + bool key_found = false; + stream_rewind(dict->stream); + while(!key_found) { //-V654 + if(!stream_read_line(dict->stream, next_line)) break; + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + furi_string_left(next_line, 12); + if(!furi_string_equal(key, next_line)) continue; + key_found = true; + } + + furi_string_free(next_line); + return key_found; +} + +bool napi_mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) { + FuriString* temp_key; + + temp_key = furi_string_alloc(); + napi_mf_classic_dict_int_to_str(key, temp_key); + bool key_found = napi_mf_classic_dict_is_key_present_str(dict, temp_key); + furi_string_free(temp_key); + return key_found; +} + +bool napi_key_already_found_for_nonce( + MfClassicDict* dict, + uint32_t uid_xor_nt1, + uint32_t nr1_enc, + uint32_t p64b, + uint32_t ar1_enc) { + bool found = false; + uint64_t k = 0; + napi_mf_classic_dict_rewind(dict); + while(napi_mf_classic_dict_get_next_key(dict, &k)) { + struct Crypto1State temp = {0, 0}; + int i; + for(i = 0; i < 24; i++) { + (&temp)->odd |= (BIT(k, 2 * i + 1) << (i ^ 3)); + (&temp)->even |= (BIT(k, 2 * i) << (i ^ 3)); + } + crypt_word_noret(&temp, uid_xor_nt1, 0); + crypt_word_noret(&temp, nr1_enc, 1); + if(ar1_enc == (crypt_word(&temp) ^ p64b)) { + found = true; + break; + } + } + return found; +} + +bool napi_mf_classic_nonces_check_presence() { + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool nonces_present = storage_common_stat(storage, MF_CLASSIC_NONCE_PATH, NULL) == FSE_OK; + + furi_record_close(RECORD_STORAGE); + + return nonces_present; +} + +MfClassicNonceArray* napi_mf_classic_nonce_array_alloc( + MfClassicDict* system_dict, + bool system_dict_exists, + MfClassicDict* user_dict, + ProgramState* program_state) { + MfClassicNonceArray* nonce_array = malloc(sizeof(MfClassicNonceArray)); + MfClassicNonce* remaining_nonce_array_init = malloc(sizeof(MfClassicNonce) * 1); + nonce_array->remaining_nonce_array = remaining_nonce_array_init; + Storage* storage = furi_record_open(RECORD_STORAGE); + nonce_array->stream = buffered_file_stream_alloc(storage); + furi_record_close(RECORD_STORAGE); + + bool array_loaded = false; + do { + // https://github.com/flipperdevices/flipperzero-firmware/blob/5134f44c09d39344a8747655c0d59864bb574b96/applications/services/storage/filesystem_api_defines.h#L8-L22 + if(!buffered_file_stream_open( + nonce_array->stream, MF_CLASSIC_NONCE_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(nonce_array->stream); + break; + } + + // Check for newline ending + if(!stream_eof(nonce_array->stream)) { + if(!stream_seek(nonce_array->stream, -1, StreamOffsetFromEnd)) break; + uint8_t last_char = 0; + if(stream_read(nonce_array->stream, &last_char, 1) != 1) break; + if(last_char != '\n') { + FURI_LOG_D(TAG, "Adding new line ending"); + if(stream_write_char(nonce_array->stream, '\n') != 1) break; + } + if(!stream_rewind(nonce_array->stream)) break; + } + + // Read total amount of nonces + FuriString* next_line; + next_line = furi_string_alloc(); + while(!(program_state->close_thread_please)) { + if(!stream_read_line(nonce_array->stream, next_line)) { + FURI_LOG_T(TAG, "No nonces left"); + break; + } + FURI_LOG_T( + TAG, + "Read line: %s, len: %zu", + furi_string_get_cstr(next_line), + furi_string_size(next_line)); + if(!furi_string_start_with_str(next_line, "Sec")) continue; + const char* next_line_cstr = furi_string_get_cstr(next_line); + MfClassicNonce res = {0}; + int i = 0; + char* endptr; + for(i = 0; i <= 17; i++) { + if(i != 0) { + next_line_cstr = strchr(next_line_cstr, ' '); + if(next_line_cstr) { + next_line_cstr++; + } else { + break; + } + } + unsigned long value = strtoul(next_line_cstr, &endptr, 16); + switch(i) { + case 5: + res.uid = value; + break; + case 7: + res.nt0 = value; + break; + case 9: + res.nr0_enc = value; + break; + case 11: + res.ar0_enc = value; + break; + case 13: + res.nt1 = value; + break; + case 15: + res.nr1_enc = value; + break; + case 17: + res.ar1_enc = value; + break; + default: + break; // Do nothing + } + next_line_cstr = endptr; + } + (program_state->total)++; + uint32_t p64b = prng_successor(res.nt1, 64); + if((system_dict_exists && + napi_key_already_found_for_nonce( + system_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc)) || + (napi_key_already_found_for_nonce( + user_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc))) { + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + FURI_LOG_I(TAG, "No key found for %8lx %8lx", res.uid, res.ar1_enc); + // TODO: Refactor + nonce_array->remaining_nonce_array = realloc( //-V701 + nonce_array->remaining_nonce_array, + sizeof(MfClassicNonce) * ((nonce_array->remaining_nonces) + 1)); + nonce_array->remaining_nonces++; + nonce_array->remaining_nonce_array[(nonce_array->remaining_nonces) - 1] = res; + nonce_array->total_nonces++; + } + furi_string_free(next_line); + buffered_file_stream_close(nonce_array->stream); + + array_loaded = true; + FURI_LOG_I(TAG, "Loaded %lu nonces", nonce_array->total_nonces); + } while(false); + + if(!array_loaded) { + free(nonce_array); + nonce_array = NULL; + } + + return nonce_array; +} + +void napi_mf_classic_nonce_array_free(MfClassicNonceArray* nonce_array) { + furi_assert(nonce_array); + furi_assert(nonce_array->stream); + + buffered_file_stream_close(nonce_array->stream); + stream_free(nonce_array->stream); + free(nonce_array); +} + +static void finished_beep() { + // Beep to indicate completion + NotificationApp* notification = furi_record_open("notification"); + notification_message(notification, &sequence_audiovisual_alert); + notification_message(notification, &sequence_display_backlight_on); + furi_record_close("notification"); +} + +void mfkey32(ProgramState* program_state) { + uint64_t found_key; // recovered key + size_t keyarray_size = 0; + uint64_t* keyarray = malloc(sizeof(uint64_t) * 1); + uint32_t i = 0, j = 0; + // Check for nonces + if(!napi_mf_classic_nonces_check_presence()) { + program_state->err = MissingNonces; + program_state->mfkey_state = Error; + free(keyarray); + return; + } + // Read dictionaries (optional) + MfClassicDict* system_dict = {0}; + bool system_dict_exists = napi_mf_classic_dict_check_presence(MfClassicDictTypeSystem); + MfClassicDict* user_dict = {0}; + bool user_dict_exists = napi_mf_classic_dict_check_presence(MfClassicDictTypeUser); + uint32_t total_dict_keys = 0; + if(system_dict_exists) { + system_dict = napi_mf_classic_dict_alloc(MfClassicDictTypeSystem); + total_dict_keys += napi_mf_classic_dict_get_total_keys(system_dict); + } + user_dict = napi_mf_classic_dict_alloc(MfClassicDictTypeUser); + if(user_dict_exists) { + total_dict_keys += napi_mf_classic_dict_get_total_keys(user_dict); + } + user_dict_exists = true; + program_state->dict_count = total_dict_keys; + program_state->mfkey_state = DictionaryAttack; + // Read nonces + MfClassicNonceArray* nonce_arr; + nonce_arr = napi_mf_classic_nonce_array_alloc( + system_dict, system_dict_exists, user_dict, program_state); + if(system_dict_exists) { + napi_mf_classic_dict_free(system_dict); + } + if(nonce_arr->total_nonces == 0) { + // Nothing to crack + program_state->err = ZeroNonces; + program_state->mfkey_state = Error; + napi_mf_classic_nonce_array_free(nonce_arr); + napi_mf_classic_dict_free(user_dict); + free(keyarray); + return; + } + if(memmgr_get_free_heap() < MIN_RAM) { + // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed + eta_round_time *= 2; + eta_total_time *= 2; + MSB_LIMIT /= 2; + } + program_state->mfkey_state = MfkeyAttack; + // TODO: Work backwards on this array and free memory + for(i = 0; i < nonce_arr->total_nonces; i++) { + MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; + uint32_t p64 = prng_successor(next_nonce.nt0, 64); + uint32_t p64b = prng_successor(next_nonce.nt1, 64); + if(key_already_found_for_nonce( + keyarray, + keyarray_size, + next_nonce.uid ^ next_nonce.nt1, + next_nonce.nr1_enc, + p64b, + next_nonce.ar1_enc)) { + nonce_arr->remaining_nonces--; + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + FURI_LOG_I(TAG, "Cracking %8lx %8lx", next_nonce.uid, next_nonce.ar1_enc); + struct Crypto1Params p = { + 0, + next_nonce.nr0_enc, + next_nonce.uid ^ next_nonce.nt0, + next_nonce.uid ^ next_nonce.nt1, + next_nonce.nr1_enc, + p64b, + next_nonce.ar1_enc}; + if(!recover(&p, next_nonce.ar0_enc ^ p64, program_state)) { + if(program_state->close_thread_please) { + break; + } + // No key found in recover() + (program_state->num_completed)++; + continue; + } + (program_state->cracked)++; + (program_state->num_completed)++; + found_key = p.key; + bool already_found = false; + for(j = 0; j < keyarray_size; j++) { + if(keyarray[j] == found_key) { + already_found = true; + break; + } + } + if(already_found == false) { + // New key + keyarray = realloc(keyarray, sizeof(uint64_t) * (keyarray_size + 1)); //-V701 + keyarray_size += 1; + keyarray[keyarray_size - 1] = found_key; + (program_state->unique_cracked)++; + } + } + // TODO: Update display to show all keys were found + // TODO: Prepend found key(s) to user dictionary file + //FURI_LOG_I(TAG, "Unique keys found:"); + for(i = 0; i < keyarray_size; i++) { + //FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]); + FuriString* temp_key = furi_string_alloc(); + furi_string_cat_printf(temp_key, "%012" PRIX64, keyarray[i]); + napi_mf_classic_dict_add_key_str(user_dict, temp_key); + furi_string_free(temp_key); + } + if(keyarray_size > 0) { + // TODO: Should we use DolphinDeedNfcMfcAdd? + DOLPHIN_DEED(DolphinDeedNfcMfcAdd); + } + napi_mf_classic_nonce_array_free(nonce_arr); + napi_mf_classic_dict_free(user_dict); + free(keyarray); + //FURI_LOG_I(TAG, "mfkey32 function completed normally"); // DEBUG + program_state->mfkey_state = Complete; + // No need to alert the user if they asked it to stop + if(!(program_state->close_thread_please)) { + finished_beep(); + } + return; +} + +// Screen is 128x64 px +static void render_callback(Canvas* const canvas, void* ctx) { + furi_assert(ctx); + ProgramState* program_state = ctx; + furi_mutex_acquire(program_state->mutex, FuriWaitForever); + char draw_str[44] = {}; + canvas_clear(canvas); + canvas_draw_frame(canvas, 0, 0, 128, 64); + canvas_draw_frame(canvas, 0, 15, 128, 64); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "Mfkey32"); + canvas_draw_icon(canvas, 114, 4, &I_mfkey); + if(program_state->is_thread_running && program_state->mfkey_state == MfkeyAttack) { + float eta_round = (float)1 - ((float)program_state->eta_round / (float)eta_round_time); + float eta_total = (float)1 - ((float)program_state->eta_total / (float)eta_total_time); + float progress = (float)program_state->num_completed / (float)program_state->total; + if(eta_round < 0) { + // Round ETA miscalculated + eta_round = 1; + program_state->eta_round = 0; + } + if(eta_total < 0) { + // Total ETA miscalculated + eta_total = 1; + program_state->eta_total = 0; + } + canvas_set_font(canvas, FontSecondary); + snprintf( + draw_str, + sizeof(draw_str), + "Cracking: %d/%d - in prog.", + program_state->num_completed, + program_state->total); + elements_progress_bar_with_text(canvas, 5, 18, 118, progress, draw_str); + snprintf( + draw_str, + sizeof(draw_str), + "Round: %d/%d - ETA %02d Sec", + (program_state->search) + 1, // Zero indexed + 256 / MSB_LIMIT, + program_state->eta_round); + elements_progress_bar_with_text(canvas, 5, 31, 118, eta_round, draw_str); + snprintf(draw_str, sizeof(draw_str), "Total ETA %03d Sec", program_state->eta_total); + elements_progress_bar_with_text(canvas, 5, 44, 118, eta_total, draw_str); + } else if(program_state->is_thread_running && program_state->mfkey_state == DictionaryAttack) { + canvas_set_font(canvas, FontSecondary); + snprintf( + draw_str, sizeof(draw_str), "Dict solves: %d (in progress)", program_state->cracked); + canvas_draw_str_aligned(canvas, 10, 18, AlignLeft, AlignTop, draw_str); + snprintf(draw_str, sizeof(draw_str), "Keys in dict: %d", program_state->dict_count); + canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str); + } else if(program_state->mfkey_state == Complete) { + // TODO: Scrollable list view to see cracked keys if user presses down + elements_progress_bar_with_text(canvas, 5, 18, 118, 1, draw_str); + canvas_set_font(canvas, FontSecondary); + snprintf(draw_str, sizeof(draw_str), "Complete"); + canvas_draw_str_aligned(canvas, 40, 31, AlignLeft, AlignTop, draw_str); + snprintf( + draw_str, + sizeof(draw_str), + "Keys added to user dict: %d", + program_state->unique_cracked); + canvas_draw_str_aligned(canvas, 10, 41, AlignLeft, AlignTop, draw_str); + } else if(program_state->mfkey_state == Ready) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready"); + elements_button_center(canvas, "Start"); + elements_button_right(canvas, "Help"); + } else if(program_state->mfkey_state == Help) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces using"); + canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "Detect Reader."); + canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "Developers: noproto, AG"); + canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "Thanks: bettse"); + } else if(program_state->mfkey_state == Error) { + canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Error"); + canvas_set_font(canvas, FontSecondary); + if(program_state->err == MissingNonces) { + canvas_draw_str_aligned(canvas, 25, 36, AlignLeft, AlignTop, "No nonces found"); + } else if(program_state->err == ZeroNonces) { + canvas_draw_str_aligned(canvas, 15, 36, AlignLeft, AlignTop, "Nonces already cracked"); + } else { + // Unhandled error + } + } else { + // Unhandled program state + } + furi_mutex_release(program_state->mutex); +} + +static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + PluginEvent event = {.type = EventTypeKey, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void mfkey32_state_init(ProgramState* program_state) { + program_state->is_thread_running = false; + program_state->mfkey_state = Ready; + program_state->cracked = 0; + program_state->unique_cracked = 0; + program_state->num_completed = 0; + program_state->total = 0; + program_state->dict_count = 0; +} + +// Entrypoint for worker thread +static int32_t mfkey32_worker_thread(void* ctx) { + ProgramState* program_state = ctx; + program_state->is_thread_running = true; + program_state->mfkey_state = Initializing; + //FURI_LOG_I(TAG, "Hello from the mfkey32 worker thread"); // DEBUG + mfkey32(program_state); + program_state->is_thread_running = false; + return 0; +} + +void start_mfkey32_thread(ProgramState* program_state) { + if(!program_state->is_thread_running) { + furi_thread_start(program_state->mfkeythread); + } +} + +int32_t mfkey32_main() { + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); + + ProgramState* program_state = malloc(sizeof(ProgramState)); + + mfkey32_state_init(program_state); + + program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(!program_state->mutex) { + FURI_LOG_E(TAG, "cannot create mutex\r\n"); + free(program_state); + return 255; + } + + // Set system callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, render_callback, program_state); + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Open GUI and register view_port + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + program_state->mfkeythread = furi_thread_alloc(); + furi_thread_set_name(program_state->mfkeythread, "Mfkey32 Worker"); + furi_thread_set_stack_size(program_state->mfkeythread, 2048); + furi_thread_set_context(program_state->mfkeythread, program_state); + furi_thread_set_callback(program_state->mfkeythread, mfkey32_worker_thread); + + PluginEvent event; + for(bool main_loop = true; main_loop;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); + + furi_mutex_acquire(program_state->mutex, FuriWaitForever); + + if(event_status == FuriStatusOk) { + // press events + if(event.type == EventTypeKey) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + case InputKeyUp: + break; + case InputKeyDown: + break; + case InputKeyRight: + if(!program_state->is_thread_running && + program_state->mfkey_state == Ready) { + program_state->mfkey_state = Help; + view_port_update(view_port); + } + break; + case InputKeyLeft: + break; + case InputKeyOk: + if(!program_state->is_thread_running && + program_state->mfkey_state == Ready) { + start_mfkey32_thread(program_state); + view_port_update(view_port); + } + break; + case InputKeyBack: + if(!program_state->is_thread_running && + program_state->mfkey_state == Help) { + program_state->mfkey_state = Ready; + view_port_update(view_port); + } else { + program_state->close_thread_please = true; + if(program_state->is_thread_running && program_state->mfkeythread) { + // Wait until thread is finished + furi_thread_join(program_state->mfkeythread); + } + program_state->close_thread_please = false; + main_loop = false; + } + break; + default: + break; + } + } + } + } + + view_port_update(view_port); + furi_mutex_release(program_state->mutex); + } + + furi_thread_free(program_state->mfkeythread); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close("gui"); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_mutex_free(program_state->mutex); + free(program_state); + + return 0; +} diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c index 3c4f9dba1..04515f24f 100644 --- a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c +++ b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c @@ -18,7 +18,7 @@ void nfc_scene_mfkey_complete_on_enter(void* context) { AlignCenter, AlignCenter, FontSecondary, - "Now use mfkey32v2\nto extract keys"); + "Now use Mfkey32\nto extract keys"); widget_add_button_element( nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_complete_callback, nfc); @@ -46,4 +46,4 @@ void nfc_scene_mfkey_complete_on_exit(void* context) { Nfc* nfc = context; widget_reset(nfc->widget); -} \ No newline at end of file +} From eebc6241b7aae4ca55aa76c1b37c1f924e72a58f Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 9 May 2023 07:06:44 +0300 Subject: [PATCH 157/216] [FL-3302] ble: attempt to handle hardfaulted c2 (#2653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ble: attempt to handle hardfaulted c2 * MfKey32: nicer macros * FuriHal: slightly different core2 hardfault message * Update ReadMe Co-authored-by: あく --- ReadMe.md | 1 - applications/external/mfkey32/mfkey32.c | 2 +- firmware/targets/f7/ble_glue/ble_glue.c | 20 +++++++++ lib/ReadMe.md | 57 +++++++++++++++---------- lib/stm32wb.scons | 1 + 5 files changed, 56 insertions(+), 25 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 411f5b41d..b60d66fbd 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -99,7 +99,6 @@ Make sure your Flipper is on, and your firmware is functioning. Connect your Fli - `applications` - applications and services used in firmware - `assets` - assets used by applications and services - `furi` - Furi Core: OS-level primitives and helpers -- `debug` - debug tool: GDB plugins, an SVD file, etc. - `documentation` - documentation generation system configs and input files - `firmware` - firmware source code - `lib` - our and 3rd party libraries, drivers, etc. diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c index 2934d837a..d4b2d3e4a 100644 --- a/applications/external/mfkey32/mfkey32.c +++ b/applications/external/mfkey32/mfkey32.c @@ -41,7 +41,7 @@ #define BIT(x, n) ((x) >> (n)&1) #define BEBIT(x, n) BIT(x, (n) ^ 24) #define SWAPENDIAN(x) \ - (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) //-V1003 + ((x) = ((x) >> 8 & 0xff00ff) | ((x)&0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) //#define SIZEOF(arr) sizeof(arr) / sizeof(*arr) static int eta_round_time = 56; diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index c73bbd866..6b527cfca 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -54,6 +54,26 @@ void ble_glue_set_key_storage_changed_callback( ble_glue->context = context; } +/////////////////////////////////////////////////////////////////////////////// + +/* TL hook to catch hardfaults */ + +int32_t ble_glue_TL_SYS_SendCmd(uint8_t* buffer, uint16_t size) { + if(furi_hal_bt_get_hardfault_info()) { + furi_crash("ST(R) Copro(R) HardFault"); + } + + return TL_SYS_SendCmd(buffer, size); +} + +void shci_register_io_bus(tSHciIO* fops) { + /* Register IO bus services */ + fops->Init = TL_SYS_Init; + fops->Send = ble_glue_TL_SYS_SendCmd; +} + +/////////////////////////////////////////////////////////////////////////////// + void ble_glue_init() { ble_glue = malloc(sizeof(BleGlue)); ble_glue->status = BleGlueStatusStartup; diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 884a0b8c0..93236b267 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -1,27 +1,38 @@ # Structure -- `app-scened-template` - Scened template app library -- `app-template` - Template app library +- `FreeRTOS-Kernel` - FreeRTOS kernel source code +- `FreeRTOS-glue` - Extra glue to hold together FreeRTOS kernel and flipper firmware +- `ST25RFAL002` - ST25R3916 Driver and protocol stack +- `app-scened-template` - C++ app library - `callback-connector` - Callback connector library -- `drivers` - Drivers that we wrote -- `fatfs` - External storage file system +- `cmsis_core` - CMSIS Core package, contain cortex-m core headers +- `cxxheaderparser` - C++ headers parser, used by SDK bundler +- `digital_signal` - Digital signal library: used by NFC for software implemented protocols +- `drivers` - Various flipper drivers +- `fatfs` - FatFS file system driver +- `flipper_application` - Flipper application library, used for FAPs - `flipper_format` - Flipper File Format library -- `fnv1a-hash` - Fnv1a hash library -- `heatshrink` - Image compression library -- `infrared` - Infrared library -- `libusb_stm32` - STM32 USB library -- `littlefs` - Internal storage file system -- `micro-ecc` - Elliptic Curve Crytography library -- `microtar` - TAR archive support library -- `mlib` - Algorithms and containers -- `nanopb` - Nano Protobuf library -- `nfc` - Nfc library -- `one_wire` - One wire library -- `qrcode` - Qr code generator library -- `ST25RFAL002` - ST253916 driver and NFC hal -- `stm32wb_cmsis` - STM32WB series CMSIS component -- `stm32wb_copro` - STM32WB Coprocessor fimrware + WPAN library -- `stm32wb_hal_driver` - STM32WB series HAL -- `subghz` - SubGhz library -- `toolbox` - Toolbox of things that we are using but don't place in core -- `u8g2` - Graphics library that we use to draw GUI +- `fnv1a-hash` - FNV-1a hash library +- `heatshrink` - Heatshrink compression library +- `ibutton` - ibutton library, used by iButton application +- `infrared` - Infrared library, used by Infrared application +- `lfrfid` - LF-RFID library, used by LF RFID application +- `libusb_stm32` - LibUSB for STM32 series MCU +- `littlefs` - LittleFS file system driver, used by internal storage +- `mbedtls` - MbedTLS cryptography library +- `micro-ecc` - MicroECC cryptography library +- `microtar` - MicroTAR library +- `mlib` - M-Lib C containers library +- `nanopb` - NanoPB library, protobuf implementation for MCU +- `nfc` - NFC library, used by NFC application +- `one_wire` - OneWire library, used by iButton application +- `print` - Tiny printf implementation +- `pulse_reader` - Pulse Reader library used by NFC for software implemented protocols +- `qrcode` - QR-Code library +- `stm32wb_cmsis` - STM32WB series CMSIS headers, extends CMSIS Core +- `stm32wb_copro` - STM32WB Copro library: contains WPAN and radio co-processor firmware +- `stm32wb_hal` - STM32WB HAL library, extends STM32WB CMSIS and provides HAL +- `subghz` - Subghz library, used by SubGhz application +- `toolbox` - Toolbox library, contains various things that is used by flipper firmware +- `u8g2` - u8g2 graphics library, used by GUI subsystem +- `update_util` - update utilities library, used by updater \ No newline at end of file diff --git a/lib/stm32wb.scons b/lib/stm32wb.scons index 9c184872b..7cb2fa8bd 100644 --- a/lib/stm32wb.scons +++ b/lib/stm32wb.scons @@ -48,6 +48,7 @@ sources += Glob( ) sources += Glob( "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/*_tl*.c", + exclude="stm32wb_copro/wpan/interface/patterns/ble_thread/tl/shci_tl_if.c", source=True, ) sources += [ From b99d309feb9628e9c6aa910409cb735c4a31d5a2 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 12:07:36 +0300 Subject: [PATCH 158/216] SubGhz: moving "txrx" entity to a separate file --- .../subghz_frequency_analyzer_worker.c | 2 +- .../subghz/scenes/subghz_scene_decode_raw.c | 12 +- .../subghz/scenes/subghz_scene_need_saving.c | 3 +- .../subghz/scenes/subghz_scene_read_raw.c | 37 +- .../subghz/scenes/subghz_scene_receiver.c | 42 +- .../scenes/subghz_scene_receiver_config.c | 75 +- .../scenes/subghz_scene_receiver_info.c | 45 +- .../main/subghz/scenes/subghz_scene_rpc.c | 12 +- .../subghz/scenes/subghz_scene_save_name.c | 7 +- .../subghz/scenes/subghz_scene_save_success.c | 2 +- .../main/subghz/scenes/subghz_scene_set_cnt.c | 4 +- .../main/subghz/scenes/subghz_scene_set_fix.c | 2 +- .../subghz/scenes/subghz_scene_set_seed.c | 38 +- .../subghz/scenes/subghz_scene_set_type.c | 99 +-- .../subghz/scenes/subghz_scene_transmitter.c | 15 +- applications/main/subghz/subghz.c | 47 +- applications/main/subghz/subghz_i.c | 757 +----------------- applications/main/subghz/subghz_i.h | 159 +--- applications/main/subghz/subghz_radio.c | 723 +++++++++++++++++ applications/main/subghz/subghz_radio.h | 160 ++++ 20 files changed, 1161 insertions(+), 1080 deletions(-) create mode 100644 applications/main/subghz/subghz_radio.c create mode 100644 applications/main/subghz/subghz_radio.h diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index ab90547cb..34f7e8cff 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -278,7 +278,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); SubGhz* subghz = context; - instance->setting = subghz->setting; + instance->setting = subghz->txrx->setting; instance->trigger_level = subghz->last_settings->frequency_analyzer_trigger; //instance->trigger_level = SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD; return instance; diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 639db146f..955e0df89 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -87,12 +87,13 @@ bool subghz_scene_decode_raw_start(SubGhz* subghz) { FuriString* file_name = furi_string_alloc(); bool success = false; do { - if(!flipper_format_rewind(subghz->txrx->fff_data)) { + if(!flipper_format_rewind(subghz_txtx_get_fff_data(subghz->txrx))) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", file_name)) { + if(!flipper_format_read_string( + subghz_txtx_get_fff_data(subghz->txrx), "File_name", file_name)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -193,7 +194,7 @@ void subghz_scene_decode_raw_on_enter(void* context) { } furi_string_free(item_name); furi_string_free(item_time); - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); } subghz_scene_receiver_update_statusbar(subghz); @@ -208,7 +209,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { switch(event.event) { case SubGhzCustomEventViewReceiverBack: subghz->decode_raw_state = SubGhzDecodeRawStateStart; - subghz->txrx->idx_menu_chosen = 0; + subghz->idx_menu_chosen = 0; subghz->in_decoder_scene = false; subghz->in_decoder_scene_skip = false; @@ -227,8 +228,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case SubGhzCustomEventViewReceiverOK: - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); subghz->state_notifications = SubGhzNotificationStateIDLE; subghz->in_decoder_scene = true; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index f6029e2c0..e64f75ef7 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -48,7 +48,8 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneExit) { if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateExit) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_preset_init( + subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index c2b0e5d35..9abc24523 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -13,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { //set the path to read the file FuriString* temp_str = furi_string_alloc(); do { - if(!flipper_format_rewind(subghz->txrx->fff_data)) { + if(!flipper_format_rewind(subghz_txtx_get_fff_data(subghz->txrx))) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) { + if(!flipper_format_read_string( + subghz_txtx_get_fff_data(subghz->txrx), "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -127,7 +128,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); //Stop save file subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -141,13 +142,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { //Restore default setting if(subghz->raw_send_only) { subghz_preset_init( - subghz, + subghz->txrx, "AM650", - subghz_setting_get_default_frequency(subghz->setting), + subghz_setting_get_default_frequency(subghz->txrx->setting), NULL, 0); } else { - subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_preset_init( + subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { @@ -162,7 +164,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReadRAWTXRXStop: - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; consumed = true; break; @@ -212,8 +214,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz); - if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { + subghz_txrx_stop(subghz->txrx); + if(!subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( subghz->subghz_read_raw, @@ -245,13 +247,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); subghz_read_raw_stop_send(subghz->subghz_read_raw); consumed = true; break; case SubGhzCustomEventViewReadRAWIDLE: - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); size_t spl_count = subghz_protocol_raw_get_sample_write( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); @@ -262,7 +264,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(temp_str)); + subghz_txtx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); furi_string_free(temp_str); if(spl_count > 0) { @@ -286,12 +288,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { RAW_FILE_NAME, subghz->txrx->preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); subghz_begin( - subghz, + subghz->txrx, subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); + subghz->txrx->setting, + furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); subghz->state_notifications = SubGhzNotificationStateRx; subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); @@ -355,7 +358,7 @@ void subghz_scene_read_raw_on_exit(void* context) { SubGhz* subghz = context; //Stop CC1101 - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index d52e37ff9..766810a04 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -122,7 +122,7 @@ void subghz_scene_receiver_on_enter(void* context) { FuriString* item_time = furi_string_alloc(); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { - subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_preset_init(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); subghz_history_reset(subghz->txrx->history); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } @@ -154,7 +154,7 @@ void subghz_scene_receiver_on_enter(void* context) { // TODO: Replace with proper solution based on protocol flags, remove kostily and velosipedy from here // Needs to be done after subghz refactoring merge!!! - if(subghz->txrx->ignore_starline == true) { + if(subghz->ignore_starline == true) { SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; protocoldecoderbase = subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Star Line"); @@ -163,7 +163,7 @@ void subghz_scene_receiver_on_enter(void* context) { protocoldecoderbase, NULL, subghz->txrx->receiver); } } - if(subghz->txrx->ignore_auto_alarms == true) { + if(subghz->ignore_auto_alarms == true) { SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; protocoldecoderbase = subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "KIA Seed"); @@ -179,7 +179,7 @@ void subghz_scene_receiver_on_enter(void* context) { protocoldecoderbase, NULL, subghz->txrx->receiver); } } - if(subghz->txrx->ignore_magellan == true) { + if(subghz->ignore_magellan == true) { SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; protocoldecoderbase = subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Magellan"); @@ -190,13 +190,13 @@ void subghz_scene_receiver_on_enter(void* context) { } subghz->state_notifications = SubGhzNotificationStateRx; - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); subghz_begin( - subghz, + subghz->txrx, subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( @@ -214,9 +214,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverBack: // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz); - subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); - subghz->txrx->idx_menu_chosen = 0; + subghz_txrx_stop(subghz->txrx); + subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { @@ -224,7 +224,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_preset_init( + subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } @@ -232,17 +233,15 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReceiverOK: // Show file info, scene: receiver_info - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverDeleteItem: - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->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_history_delete_item(subghz->txrx->history, subghz->idx_menu_chosen); subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); subghz_scene_receiver_update_statusbar(subghz); @@ -250,8 +249,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { break; case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz->txrx->idx_menu_chosen = - subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_set_scene_state( subghz->scene_manager, SubGhzViewIdReceiver, SubGhzCustomEventManagerSet); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); @@ -269,8 +267,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz_hopper_get_state(subghz) != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_hopper_update(subghz->txrx); subghz_scene_receiver_update_statusbar(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index de78e002b..f677739fd 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -93,12 +93,12 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) { - if(value == subghz_setting_get_frequency(subghz->setting, i)) { + for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->txrx->setting); i++) { + if(value == subghz_setting_get_frequency(subghz->txrx->setting, i)) { index = i; break; } else { - index = subghz_setting_get_frequency_default_index(subghz->setting); + index = subghz_setting_get_frequency_default_index(subghz->txrx->setting); } } return index; @@ -108,12 +108,12 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) { + for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->txrx->setting); i++) { + if(!strcmp(subghz_setting_get_preset_name(subghz->txrx->setting, i), preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz->setting); + // index = subghz_setting_get_frequency_default_index(subghz->txrx->setting); } } return index; @@ -143,37 +143,39 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - if(subghz_hopper_get_state(subghz) == SubGhzHopperStateOFF) { + if(subghz_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000); + subghz_setting_get_frequency(subghz->txrx->setting, index) / 1000000, + (subghz_setting_get_frequency(subghz->txrx->setting, index) % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index); + subghz->txrx->preset->frequency = + subghz_setting_get_frequency(subghz->txrx->setting, index); subghz->last_settings->frequency = subghz->txrx->preset->frequency; - subghz_setting_set_default_frequency(subghz->setting, subghz->txrx->preset->frequency); + subghz_setting_set_default_frequency( + subghz->txrx->setting, subghz->txrx->preset->frequency); } else { variable_item_set_current_value_index( - item, subghz_setting_get_frequency_default_index(subghz->setting)); + item, subghz_setting_get_frequency_default_index(subghz->txrx->setting)); } } static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - const char* preset_name = subghz_setting_get_preset_name(subghz->setting, index); + const char* preset_name = subghz_setting_get_preset_name(subghz->txrx->setting, index); variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; subghz_preset_init( - subghz, + subghz->txrx, preset_name, subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, index), - subghz_setting_get_preset_data_size(subghz->setting, index)); + subghz_setting_get_preset_data(subghz->txrx->setting, index), + subghz_setting_get_preset_data_size(subghz->txrx->setting, index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { @@ -187,17 +189,18 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); + subghz_setting_get_default_frequency(subghz->txrx->setting) / 1000000, + (subghz_setting_get_default_frequency(subghz->txrx->setting) % 1000000) / 10000); variable_item_set_current_value_text( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), text_buf); - subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting); + subghz->txrx->preset->frequency = + subghz_setting_get_default_frequency(subghz->txrx->setting); variable_item_set_current_value_index( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + subghz_setting_get_frequency_default_index(subghz->txrx->setting)); } else { variable_item_set_current_value_text( (VariableItem*)scene_manager_get_scene_state( @@ -206,10 +209,10 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) variable_item_set_current_value_index( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); + subghz_setting_get_frequency_default_index(subghz->txrx->setting)); } - subghz_hopper_set_state(subghz, hopping_value[index]); + subghz_hopper_set_state(subghz->txrx, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -217,7 +220,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz_speaker_set_state(subghz, speaker_value[index]); + subghz_speaker_set_state(subghz->txrx, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -242,7 +245,7 @@ static void subghz_scene_receiver_config_set_starline(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, starline_text[index]); - subghz->txrx->ignore_starline = (index == 1); + subghz->ignore_starline = (index == 1); } static void subghz_scene_receiver_config_set_auto_alarms(VariableItem* item) { @@ -250,7 +253,7 @@ static void subghz_scene_receiver_config_set_auto_alarms(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, auto_alarms_text[index]); - subghz->txrx->ignore_auto_alarms = (index == 1); + subghz->ignore_auto_alarms = (index == 1); } static void subghz_scene_receiver_config_set_magellan(VariableItem* item) { @@ -258,7 +261,7 @@ static void subghz_scene_receiver_config_set_magellan(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, magellan_text[index]); - subghz->txrx->ignore_magellan = (index == 1); + subghz->ignore_magellan = (index == 1); } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -278,7 +281,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz->setting), + subghz_setting_get_frequency_count(subghz->txrx->setting), subghz_scene_receiver_config_set_frequency, subghz); value_index = @@ -291,21 +294,21 @@ void subghz_scene_receiver_config_on_enter(void* context) { text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->setting, value_index) / 1000000, - (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000); + subghz_setting_get_frequency(subghz->txrx->setting, value_index) / 1000000, + (subghz_setting_get_frequency(subghz->txrx->setting, value_index) % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz->setting), + subghz_setting_get_preset_count(subghz->txrx->setting), subghz_scene_receiver_config_set_preset, subghz); value_index = subghz_scene_receiver_config_next_preset( furi_string_get_cstr(subghz->txrx->preset->name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->setting, value_index)); + item, subghz_setting_get_preset_name(subghz->txrx->setting, value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { @@ -317,7 +320,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz_hopper_get_state(subghz), hopping_value, HOPPING_COUNT, subghz); + subghz_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } @@ -344,7 +347,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_starline, subghz); - value_index = subghz->txrx->ignore_starline; + value_index = subghz->ignore_starline; variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, starline_text[value_index]); @@ -355,7 +358,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_auto_alarms, subghz); - value_index = subghz->txrx->ignore_auto_alarms; + value_index = subghz->ignore_auto_alarms; variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_alarms_text[value_index]); @@ -366,7 +369,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_magellan, subghz); - value_index = subghz->txrx->ignore_magellan; + value_index = subghz->ignore_magellan; variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, magellan_text[value_index]); } @@ -379,7 +382,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_speaker, subghz); value_index = - value_index_uint32(subghz_speaker_get_state(subghz), speaker_value, SPEAKER_COUNT); + value_index_uint32(subghz_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index dd637c1eb..3c53ac021 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -25,18 +25,18 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhz* subghz = context; subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( subghz->txrx->receiver, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz_history_get_protocol_name(subghz->txrx->history, subghz->idx_menu_chosen)); if(subghz->txrx->decoder_result) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( subghz->txrx->decoder_result, - subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz_history_get_raw_data(subghz->txrx->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = - subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); + subghz_history_get_radio_preset(subghz->txrx->history, subghz->idx_menu_chosen); subghz_preset_init( - subghz, + subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, preset->data, @@ -122,25 +122,24 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { //CC1101 Stop RX -> Start TX - subghz_subghz_hopper_set_pause(subghz); + subghz_subghz_hopper_set_pause(subghz->txrx); - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } if(!subghz_tx_start( - subghz, - subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { - subghz_txrx_stop(subghz); + subghz->txrx, + subghz_history_get_raw_data(subghz->txrx->history, subghz->idx_menu_chosen))) { + subghz_txrx_stop(subghz->txrx); subghz_begin( - subghz, + subghz->txrx, subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); - subghz_hopper_remove_pause(subghz); + subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } else { subghz->state_notifications = SubGhzNotificationStateTx; @@ -153,24 +152,24 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); if(!subghz->in_decoder_scene) { subghz_begin( - subghz, + subghz->txrx, subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz, subghz->txrx->preset->frequency); + subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); - subghz_hopper_remove_pause(subghz); + subghz_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); + subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } @@ -187,8 +186,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz_hopper_get_state(subghz) != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz); + if(subghz_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_hopper_update(subghz->txrx); } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 4d6806a9d..2af4112cf 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -42,9 +42,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz_txrx_get_state(subghz) == SubGhzTxRxStateSleep) && + if((subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateSleep) && (state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz->txrx->fff_data); + result = subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx)); if(result) subghz_blink_start(subghz); } if(!result) { @@ -56,8 +56,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz_txrx_get_state(subghz) == SubGhzTxRxStateTx) { - subghz_txrx_stop(subghz); + if(subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateTx) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); result = true; } @@ -96,8 +96,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - if(subghz_txrx_get_state(subghz) == SubGhzTxRxStateTx) { - subghz_txrx_stop(subghz); + if(subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateTx) { + subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 2bb13f184..f31d4be79 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -146,7 +146,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( subghz, - subghz->txrx->fff_data, + subghz_txtx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, @@ -156,7 +156,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { subghz_save_protocol_to_file( subghz, subghz_history_get_raw_data( - subghz->txrx->history, subghz->txrx->idx_menu_chosen), + subghz->txrx->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } @@ -164,7 +164,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( - subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); + subghz_txtx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index 0a7fd8686..ad37da086 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -39,7 +39,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) } } else { subghz->decode_raw_state = SubGhzDecodeRawStateStart; - subghz->txrx->idx_menu_chosen = 0; + subghz->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) { diff --git a/applications/main/subghz/scenes/subghz_scene_set_cnt.c b/applications/main/subghz/scenes/subghz_scene_set_cnt.c index 62ef581ff..4faff7bbb 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_cnt.c +++ b/applications/main/subghz/scenes/subghz_scene_set_cnt.c @@ -24,7 +24,7 @@ void subghz_scene_set_cnt_on_enter(void* context) { subghz_scene_set_cnt_byte_input_callback, NULL, subghz, - subghz->txrx->secure_data->cnt, + subghz->secure_data->cnt, 2); break; case SubmenuIndexFaacSLH_433: @@ -35,7 +35,7 @@ void subghz_scene_set_cnt_on_enter(void* context) { subghz_scene_set_cnt_byte_input_callback, NULL, subghz, - subghz->txrx->secure_data->cnt, + subghz->secure_data->cnt, 3); break; default: diff --git a/applications/main/subghz/scenes/subghz_scene_set_fix.c b/applications/main/subghz/scenes/subghz_scene_set_fix.c index 01431dac6..7564fb24d 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_fix.c +++ b/applications/main/subghz/scenes/subghz_scene_set_fix.c @@ -19,7 +19,7 @@ void subghz_scene_set_fix_on_enter(void* context) { subghz_scene_set_fix_byte_input_callback, NULL, subghz, - subghz->txrx->secure_data->fix, + subghz->secure_data->fix, 4); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 336331126..e416d8c2d 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -19,7 +19,7 @@ void subghz_scene_set_seed_on_enter(void* context) { subghz_scene_set_seed_byte_input_callback, NULL, subghz, - subghz->txrx->secure_data->seed, + subghz->secure_data->seed, 4); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } @@ -36,20 +36,16 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { switch(state) { case SubmenuIndexBFTClone: - fix_part = subghz->txrx->secure_data->fix[0] << 24 | - subghz->txrx->secure_data->fix[1] << 16 | - subghz->txrx->secure_data->fix[2] << 8 | - subghz->txrx->secure_data->fix[3]; + fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 | + subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3]; - cnt = subghz->txrx->secure_data->cnt[0] << 8 | subghz->txrx->secure_data->cnt[1]; + cnt = subghz->secure_data->cnt[0] << 8 | subghz->secure_data->cnt[1]; - seed = subghz->txrx->secure_data->seed[0] << 24 | - subghz->txrx->secure_data->seed[1] << 16 | - subghz->txrx->secure_data->seed[2] << 8 | - subghz->txrx->secure_data->seed[3]; + seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 | + subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( - subghz, + subghz->txrx, "AM650", 433920000, fix_part & 0x0FFFFFFF, @@ -67,22 +63,18 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexFaacSLH_433: case SubmenuIndexFaacSLH_868: - fix_part = subghz->txrx->secure_data->fix[0] << 24 | - subghz->txrx->secure_data->fix[1] << 16 | - subghz->txrx->secure_data->fix[2] << 8 | - subghz->txrx->secure_data->fix[3]; + fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 | + subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3]; - cnt = subghz->txrx->secure_data->cnt[0] << 16 | - subghz->txrx->secure_data->cnt[1] << 8 | subghz->txrx->secure_data->cnt[2]; + cnt = subghz->secure_data->cnt[0] << 16 | subghz->secure_data->cnt[1] << 8 | + subghz->secure_data->cnt[2]; - seed = subghz->txrx->secure_data->seed[0] << 24 | - subghz->txrx->secure_data->seed[1] << 16 | - subghz->txrx->secure_data->seed[2] << 8 | - subghz->txrx->secure_data->seed[3]; + seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 | + subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; if(state == SubmenuIndexFaacSLH_433) { generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( - subghz, + subghz->txrx, "AM650", 433920000, fix_part >> 4, @@ -92,7 +84,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { "FAAC_SLH"); } else if(state == SubmenuIndexFaacSLH_868) { generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( - subghz, + subghz->txrx, "AM650", 868350000, fix_part >> 4, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 2ce806067..4bbf1c769 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -292,7 +292,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { - uint32_t key = subghz_random_serial(); + uint32_t key = (uint32_t)rand(); switch(event.event) { case SubmenuIndexFaacSLH_868: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); @@ -306,68 +306,68 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexPricenton433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 generated_protocol = subghz_gen_data_protocol_and_te( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexPricenton315: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 generated_protocol = subghz_gen_data_protocol_and_te( - subghz, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); + subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexCAME12bit868: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); + subghz->txrx, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit868: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); + subghz->txrx, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); + subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexBETT_433: key = (key & 0x0000FFF0); generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_BETT_NAME, key, 18); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_BETT_NAME, key, 18); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); generated_protocol = subghz_gen_data_protocol( - subghz, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); + subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexBeninca433: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 433920000, (key & 0x000FFF00) | 0x00800080, @@ -382,7 +382,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexBeninca868: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 868350000, (key & 0x000FFF00) | 0x00800080, @@ -397,7 +397,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexAllmatic433: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 433920000, (key & 0x00FFFF00) | 0x01000011, @@ -412,7 +412,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexAllmatic868: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 868350000, (key & 0x00FFFF00) | 0x01000011, @@ -427,7 +427,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexElmesElectronic: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 433920000, (key & 0x00FFFFFF) | 0x02000000, @@ -442,7 +442,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexANMotorsAT4: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 433920000, (key & 0x000FFFFF) | 0x04700000, @@ -457,7 +457,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexAprimatic: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, + subghz->txrx, "AM650", 433920000, (key & 0x000FFFFF) | 0x00600000, @@ -472,7 +472,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexGibidi433: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi"); + subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -481,7 +481,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexGSN: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN"); + subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -490,7 +490,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexIronLogic: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic"); + subghz->txrx, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -499,7 +499,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexSommer_FM_434: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); + subghz->txrx, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -508,7 +508,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexSommer_FM_868: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); + subghz->txrx, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -517,7 +517,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexDTMNeo433: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo"); + subghz->txrx, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -526,7 +526,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexCAMESpace: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space"); + subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -535,7 +535,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexBFTMitto: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( - subghz, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0002, key & 0x000FFFFF, "BFT"); + subghz->txrx, + "AM650", + 433920000, + key & 0x000FFFFF, + 0x2, + 0x0002, + key & 0x000FFFFF, + "BFT"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -544,7 +551,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexAlutechAT4N: generated_protocol = subghz_scene_set_type_submenu_gen_data_alutech_at_4n( - subghz, "AM650", 433920000, (key & 0x000FFFFF) | 0x00100000, 0x44, 0x0003); + subghz->txrx, "AM650", 433920000, (key & 0x000FFFFF) | 0x00100000, 0x44, 0x0003); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -553,7 +560,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexSomfyTelis: generated_protocol = subghz_scene_set_type_submenu_gen_data_somfy_telis( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003); + subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003); if(!generated_protocol) { //TODO does not use databases furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -562,7 +569,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexDoorHan_433_92: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); + subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -571,7 +578,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexDoorHan_315_00: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); + subghz->txrx, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -580,7 +587,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexNiceFlorS_433_92: generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, false); + subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, false); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -589,7 +596,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexNiceOne_433_92: generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( - subghz, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, true); + subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, true); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -598,7 +605,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexNiceSmilo_433_92: generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( - subghz, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo"); + subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo"); if(!generated_protocol) { furi_string_set( subghz->error_str, "Function requires\nan SD card with\nfresh databases."); @@ -606,29 +613,29 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 315000000); + generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 390000000); + generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexLiftMaster_433_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz, "AM650", 433920000); + generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 433920000); break; case SubmenuIndexSecPlus_v2_310_00: - generated_protocol = - subghz_gen_secplus_v2_protocol(subghz, "AM650", 310000000, key, 0x68, 0xE500000); + generated_protocol = subghz_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - generated_protocol = - subghz_gen_secplus_v2_protocol(subghz, "AM650", 315000000, key, 0x68, 0xE500000); + generated_protocol = subghz_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - generated_protocol = - subghz_gen_secplus_v2_protocol(subghz, "AM650", 390000000, key, 0x68, 0xE500000); + generated_protocol = subghz_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_433_00: - generated_protocol = - subghz_gen_secplus_v2_protocol(subghz, "AM650", 433920000, key, 0x68, 0xE500000); + generated_protocol = subghz_gen_secplus_v2_protocol( + subghz->txrx, "AM650", 433920000, key, 0x68, 0xE500000); break; default: return false; diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index ed4088ec5..375c142d1 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -23,7 +23,8 @@ bool subghz_scene_transmitter_update_data_show(void* context) { bool show_button = false; if(subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) { + subghz->txrx->decoder_result, subghz_txtx_get_fff_data(subghz->txrx)) == + SubGhzProtocolStatusOk) { subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == @@ -70,8 +71,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz); - if(subghz_tx_start(subghz, subghz->txrx->fff_data)) { + subghz_txrx_stop(subghz->txrx); + if(subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); DOLPHIN_DEED(DolphinDeedSubGhzSend); @@ -79,19 +80,19 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); if(subghz_custom_btn_get() != 0) { subghz_custom_btn_set(0); uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); - if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { + if(!subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } - subghz_txrx_stop(subghz); + subghz_txrx_stop(subghz->txrx); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } return true; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 7e6cebe98..8731bbc9d 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -180,10 +180,11 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz_test_static_get_view(subghz->subghz_test_static)); #endif + subghz->txrx = malloc(sizeof(SubGhzTxRx)); //init setting - subghz->setting = subghz_setting_alloc(); + subghz->txrx->setting = subghz_setting_alloc(); - subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user")); + subghz_setting_load(subghz->txrx->setting, EXT_PATH("subghz/assets/setting_user")); // Custom Presets load without using config file if(!alloc_for_tx_only) { @@ -193,7 +194,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"FM95", temp_fm_preset); + subghz_setting_load_custom_preset( + subghz->txrx->setting, (const char*)"FM95", temp_fm_preset); flipper_format_free(temp_fm_preset); @@ -204,7 +206,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 03 47 08 32 0B 06 15 32 14 00 13 00 12 00 11 32 10 A7 18 18 19 1D 1D 92 1C 00 1B 04 20 FB 22 17 21 B6 00 00 00 12 0E 34 60 C5 C1 C0"); flipper_format_rewind(temp_fm_preset2); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"FM15k", temp_fm_preset2); + subghz_setting_load_custom_preset( + subghz->txrx->setting, (const char*)"FM15k", temp_fm_preset2); flipper_format_free(temp_fm_preset2); @@ -215,7 +218,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset3); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"Pagers", temp_fm_preset3); + subghz_setting_load_custom_preset( + subghz->txrx->setting, (const char*)"Pagers", temp_fm_preset3); flipper_format_free(temp_fm_preset3); @@ -226,7 +230,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset4); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_1", temp_fm_preset4); + subghz_setting_load_custom_preset( + subghz->txrx->setting, (const char*)"HND_1", temp_fm_preset4); flipper_format_free(temp_fm_preset4); @@ -236,7 +241,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset5); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_2", temp_fm_preset5); + subghz_setting_load_custom_preset( + subghz->txrx->setting, (const char*)"HND_2", temp_fm_preset5); flipper_format_free(temp_fm_preset5); } @@ -253,7 +259,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->last_settings->frequency, subghz->last_settings->preset); #endif - subghz_setting_set_default_frequency(subghz->setting, subghz->last_settings->frequency); + subghz_setting_set_default_frequency( + subghz->txrx->setting, subghz->last_settings->frequency); } //init threshold rssi @@ -261,18 +268,22 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { //init Worker & Protocol & History & KeyBoard subghz_unlock(subghz); - subghz->txrx = malloc(sizeof(SubGhzTxRx)); + subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); subghz->txrx->preset->name = furi_string_alloc(); if(!alloc_for_tx_only) { - subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_preset_init(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } else { subghz_preset_init( - subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + subghz->txrx, + "AM650", + subghz_setting_get_default_frequency(subghz->txrx->setting), + NULL, + 0); } subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz_hopper_set_state(subghz, SubGhzHopperStateOFF); - subghz_speaker_set_state(subghz, SubGhzSpeakerStateDisable); + subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz_speaker_set_state(subghz->txrx, SubGhzSpeakerStateDisable); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz->txrx->debug_pin_state = false; if(!alloc_for_tx_only) { @@ -282,7 +293,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->fff_data = flipper_format_string_alloc(); - subghz->txrx->secure_data = malloc(sizeof(SecureData)); + subghz->secure_data = malloc(sizeof(SecureData)); subghz->txrx->environment = subghz_environment_alloc(); subghz_environment_set_came_atomo_rainbow_table_file_name( @@ -303,6 +314,8 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); + subghz_txrx_need_save_callback_set(subghz->txrx, subghz_save_to_file, subghz); + //Init Error_str subghz->error_str = furi_string_alloc(); @@ -319,7 +332,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz->rpc_ctx = NULL; } - subghz_speaker_off(subghz); + subghz_speaker_off(subghz->txrx); #if FURI_DEBUG // Packet Test @@ -390,7 +403,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz->gui = NULL; // setting - subghz_setting_free(subghz->setting); + subghz_setting_free(subghz->txrx->setting); if(!alloc_for_tx_only) { subghz_last_settings_free(subghz->last_settings); } @@ -412,7 +425,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { } furi_string_free(subghz->txrx->preset->name); free(subghz->txrx->preset); - free(subghz->txrx->secure_data); + free(subghz->secure_data); free(subghz->txrx); //Error string diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 0226921ad..3b9c1c695 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,38 +18,6 @@ #define TAG "SubGhz" -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size) { - furi_assert(context); - SubGhz* subghz = context; - furi_string_set(subghz->txrx->preset->name, preset_name); - subghz->txrx->preset->frequency = frequency; - subghz->txrx->preset->data = preset_data; - subghz->txrx->preset->data_size = preset_data_size; -} - -bool subghz_set_preset(SubGhz* subghz, const char* preset) { - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - furi_string_set(subghz->txrx->preset->name, "AM270"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - furi_string_set(subghz->txrx->preset->name, "AM650"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - furi_string_set(subghz->txrx->preset->name, "FM238"); - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - furi_string_set(subghz->txrx->preset->name, "FM476"); - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - furi_string_set(subghz->txrx->preset->name, "CUSTOM"); - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - return true; -} - void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) { furi_assert(subghz); if(frequency != NULL) { @@ -64,195 +32,6 @@ void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, Furi } } -void subghz_begin(SubGhz* subghz, uint8_t* preset_data) { - furi_assert(subghz); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { - furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } - furi_assert( - subghz->txrx->txrx_state != SubGhzTxRxStateRx && - subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); - subghz_speaker_on(subghz); - furi_hal_subghz_rx(); - - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); - subghz_worker_start(subghz->txrx->worker); - subghz->txrx->txrx_state = SubGhzTxRxStateRx; - return value; -} - -static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { - furi_assert(subghz); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); - if(ret) { - subghz_speaker_on(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateTx; - } - return ret; -} - -void subghz_idle(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_rx_end(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); - - if(subghz_worker_is_running(subghz->txrx->worker)) { - subghz_worker_stop(subghz->txrx->worker); - furi_hal_subghz_stop_async_rx(); - } - furi_hal_subghz_idle(); - subghz_speaker_off(subghz); - subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; -} - -void subghz_sleep(SubGhz* subghz) { - furi_assert(subghz); - furi_hal_subghz_sleep(); - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; -} - -bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { - furi_assert(subghz); - - bool ret = false; - FuriString* temp_str = furi_string_alloc(); - uint32_t repeat = 200; - do { - if(!flipper_format_rewind(flipper_format)) { - FURI_LOG_E(TAG, "Rewind error"); - break; - } - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, furi_string_get_cstr(temp_str)); - - if(subghz->txrx->transmitter) { - if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) == - SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) { - subghz_begin( - subghz, - subghz_setting_get_preset_data_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - } else { - FURI_LOG_E( - TAG, - "Unknown name preset \" %s \"", - furi_string_get_cstr(subghz->txrx->preset->name)); - subghz_begin( - subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650")); - } - if(subghz->txrx->preset->frequency) { - ret = subghz_tx(subghz, subghz->txrx->preset->frequency); - } else { - ret = subghz_tx(subghz, 433920000); - } - if(ret) { - //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, subghz->txrx->transmitter); - } else { - subghz_dialog_message_show_only_rx(subghz); - } - } else { - dialog_message_show_storage_error( - subghz->dialogs, "Error in protocol\nparameters\ndescription"); - } - } - if(!ret) { - subghz_transmitter_free(subghz->txrx->transmitter); - if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) { - subghz_idle(subghz); - } - } - - } while(false); - furi_string_free(temp_str); - return ret; -} - -void subghz_tx_stop(SubGhz* subghz) { - furi_assert(subghz); - furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx); - //Stop TX - furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(subghz->txrx->transmitter); - subghz_transmitter_free(subghz->txrx->transmitter); - - //if protocol dynamic then we save the last upload - if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && - (subghz_path_is_file(subghz->file_path))) { - subghz_save_protocol_to_file( - subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); - } - subghz_idle(subghz); - subghz_speaker_off(subghz); - notification_message(subghz->notifications, &sequence_reset_red); -} - -void subghz_txrx_stop(SubGhz* subghz) { - furi_assert(subghz); - - switch(subghz->txrx->txrx_state) { - case SubGhzTxRxStateTx: - subghz_tx_stop(subghz); - subghz_speaker_unmute(subghz); - subghz_sleep(subghz); - break; - case SubGhzTxRxStateRx: - subghz_rx_end(subghz); - subghz_speaker_mute(subghz); - subghz_sleep(subghz); - break; - - default: - break; - } -} - -SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz) { - furi_assert(subghz); - return subghz->txrx->txrx_state; -} - void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); @@ -275,7 +54,8 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); + Stream* fff_data_stream = + flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx)); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; FuriString* temp_str = furi_string_alloc(); @@ -301,6 +81,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } + //Load frequency if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_E(TAG, "Missing Frequency"); break; @@ -316,14 +97,15 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { load_key_state = SubGhzLoadKeyStateOnlyRx; break; } - subghz->txrx->preset->frequency = temp_data32; + //subghz->txrx->preset->frequency = temp_data32; + //Load preset if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; } - if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) { + if(!subghz_set_preset(subghz->txrx, furi_string_get_cstr(temp_str))) { break; } @@ -331,10 +113,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { //Todo add Custom_preset_module //delete preset if it already exists subghz_setting_delete_custom_preset( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_txrx_get_setting(subghz->txrx), + furi_string_get_cstr(subghz->txrx->preset->name)); //load custom preset from file if(!subghz_setting_load_custom_preset( - subghz->setting, + subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(subghz->txrx->preset->name), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); @@ -342,34 +125,37 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } } size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_txrx_get_setting(subghz->txrx), + furi_string_get_cstr(subghz->txrx->preset->name)); subghz_preset_init( - subghz, + subghz->txrx, furi_string_get_cstr(subghz->txrx->preset->name), - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->setting, preset_index), - subghz_setting_get_preset_data_size(subghz->setting, preset_index)); + temp_data32, + subghz_setting_get_preset_data(subghz_txrx_get_setting(subghz->txrx), preset_index), + subghz_setting_get_preset_data_size( + subghz_txrx_get_setting(subghz->txrx), preset_index)); + //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; } if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW - subghz->txrx->load_type_file = SubGhzLoadTypeFileRaw; - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); + subghz->load_type_file = SubGhzLoadTypeFileRaw; + subghz_protocol_raw_gen_fff_data(subghz_txtx_get_fff_data(subghz->txrx), file_path); } else { - subghz->txrx->load_type_file = SubGhzLoadTypeFileKey; + subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(subghz->txrx->fff_data)); + flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx))); } subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( subghz->txrx->receiver, furi_string_get_cstr(temp_str)); if(subghz->txrx->decoder_result) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data); + subghz->txrx->decoder_result, subghz_txtx_get_fff_data(subghz->txrx)); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; @@ -416,7 +202,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) { furi_assert(subghz); - return subghz->txrx->load_type_file; + return subghz->load_type_file; } bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { @@ -460,6 +246,17 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { return res; } +void subghz_save_to_file(void* context) { + furi_assert(context); + SubGhz* subghz = context; + if(subghz_path_is_file(subghz->file_path)) { + subghz_save_protocol_to_file( + subghz, + subghz_txtx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); + } +} + bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, @@ -583,151 +380,6 @@ bool subghz_path_is_file(FuriString* path) { return furi_string_end_with(path, SUBGHZ_APP_EXTENSION); } -uint32_t subghz_random_serial(void) { - return (uint32_t)rand(); -} - -void subghz_hopper_update(SubGhz* subghz) { - furi_assert(subghz); - - switch(subghz->txrx->hopper_state) { - case SubGhzHopperStateOFF: - case SubGhzHopperStatePause: - return; - case SubGhzHopperStateRSSITimeOut: - if(subghz->txrx->hopper_timeout != 0) { - subghz->txrx->hopper_timeout--; - return; - } - break; - default: - break; - } - float rssi = -127.0f; - if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { - // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); - - // Stay if RSSI is high enough - if(rssi > -90.0f) { - subghz->txrx->hopper_timeout = 10; - subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut; - return; - } - } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunning; - } - // Select next frequency - if(subghz->txrx->hopper_idx_frequency < - subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) { - subghz->txrx->hopper_idx_frequency++; - } else { - subghz->txrx->hopper_idx_frequency = 0; - } - - if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(subghz); - }; - if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_receiver_reset(subghz->txrx->receiver); - subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency( - subghz->setting, subghz->txrx->hopper_idx_frequency); - subghz_rx(subghz, subghz->txrx->preset->frequency); - } -} - -SubGhzHopperState subghz_hopper_get_state(SubGhz* subghz) { - furi_assert(subghz); - return subghz->txrx->hopper_state; -} - -void subghz_hopper_set_state(SubGhz* subghz, SubGhzHopperState state) { - furi_assert(subghz); - subghz->txrx->hopper_state = state; -} - -void subghz_hopper_remove_pause(SubGhz* subghz) { - furi_assert(subghz); - if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunning; - } -} - -void subghz_subghz_hopper_set_pause(SubGhz* subghz) { - furi_assert(subghz); - if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { - subghz->txrx->hopper_state = SubGhzHopperStatePause; - } -} - -void subghz_speaker_on(SubGhz* subghz) { - if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); - } - - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_acquire(30)) { - if(!subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } - } else { - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } -} - -void subghz_speaker_off(SubGhz* subghz) { - if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { - if(furi_hal_speaker_is_mine()) { - if(!subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - furi_hal_speaker_release(); - if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) - subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; - } - } -} - -void subghz_speaker_mute(SubGhz* subghz) { - if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - if(!subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(NULL); - } - } - } -} - -void subghz_speaker_unmute(SubGhz* subghz) { - if(subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); - } - if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { - if(furi_hal_speaker_is_mine()) { - if(!subghz->txrx->debug_pin_state) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); - } - } - } -} - -void subghz_speaker_set_state(SubGhz* subghz, SubGhzSpeakerState state) { - furi_assert(subghz); - subghz->txrx->speaker_state = state; -} - -SubGhzSpeakerState subghz_speaker_get_state(SubGhz* subghz) { - furi_assert(subghz); - return subghz->txrx->speaker_state; -} - void subghz_lock(SubGhz* subghz) { furi_assert(subghz); subghz->lock = SubGhzLockOn; @@ -752,344 +404,3 @@ SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) { furi_assert(subghz); return subghz->rx_key_state; } - -//#############Create new Key############## -#include -#include -#include -#include -#include - -bool subghz_gen_data_protocol( - void* context, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit) { - furi_assert(context); - SubGhz* subghz = context; - - bool res = false; - - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); - - if(subghz->txrx->decoder_result == NULL) { - furi_string_set(subghz->error_str, "Protocol not\nfound!"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - -bool subghz_gen_data_protocol_and_te( - SubGhz* subghz, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t te) { - furi_assert(subghz); - bool ret = false; - if(subghz_gen_data_protocol(subghz, preset_name, frequency, protocol_name, key, bit)) { - if(!flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1)) { - FURI_LOG_E(TAG, "Unable to update Te"); - } else { - ret = true; - } - } - return ret; -} - -bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - manufacture_name, - subghz->txrx->preset)) { - flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", manufacture_name); - res = true; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_keeloq_bft_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - seed, - manufacture_name, - subghz->txrx->preset)) { - res = true; - } - - if(res) { - 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] = (seed >> 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"); - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - bool nice_one) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); - subghz_preset_init(subghz, preset_name, frequency, 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, - serial, - btn, - cnt, - subghz->txrx->preset, - nice_one)) { - res = true; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_faac_slh_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - seed, - manufacture_name, - subghz->txrx->preset)) { - res = true; - } - - if(res) { - 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] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex(subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = subghz_transmitter_alloc_init( - subghz->txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_alutech_at_4n_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - subghz->txrx->preset)) { - res = true; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt) { - SubGhz* subghz = context; - - bool res = false; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); - subghz_preset_init(subghz, preset_name, frequency, NULL, 0); - - if(subghz->txrx->transmitter && - subghz_protocol_somfy_telis_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - subghz->txrx->preset)) { - res = true; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - return res; -} - -bool subghz_gen_secplus_v2_protocol( - SubGhz* subghz, - const char* name_preset, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint32_t cnt) { - furi_assert(subghz); - - bool ret = false; - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(subghz, name_preset, frequency, NULL, 0); - if(subghz->txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - serial, - btn, - cnt, - subghz->txrx->preset); - ret = true; - } - return ret; -} - -bool subghz_gen_secplus_v1_protocol(SubGhz* subghz, const char* name_preset, uint32_t frequency) { - furi_assert(subghz); - - bool ret = false; - uint32_t serial = subghz_random_serial(); - while(!subghz_protocol_secplus_v1_check_fixed(serial)) { - serial = subghz_random_serial(); - } - if(subghz_gen_data_protocol( - subghz, - name_preset, - frequency, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)serial << 32 | 0xE6000000, - 42)) { - ret = true; - } - return ret; -} \ No newline at end of file diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 73b5221cb..965538d81 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -43,6 +43,8 @@ #include "helpers/subghz_threshold_rssi.h" +#include "subghz_radio.h" + #define SUBGHZ_MAX_LEN_NAME 64 #define SUBGHZ_EXT_PRESET_NAME true @@ -58,40 +60,6 @@ typedef enum { SubGhzDecodeRawStateLoaded, } SubGhzDecodeRawState; -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolFlag filter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - SecureData* secure_data; - - SubGhzRadioPreset* preset; - SubGhzHistory* history; - uint16_t idx_menu_chosen; - - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - - SubGhzHopperState hopper_state; - SubGhzSpeakerState speaker_state; - - SubGhzTxRxState txrx_state; - - bool ignore_starline; - bool ignore_auto_alarms; - bool ignore_magellan; - - SubGhzLoadTypeFile load_type_file; - - bool debug_pin_state; -}; - -typedef struct SubGhzTxRx SubGhzTxRx; - struct SubGhz { Gui* gui; NotificationApp* notifications; @@ -124,7 +92,6 @@ struct SubGhz { SubGhzTestStatic* subghz_test_static; SubGhzTestPacket* subghz_test_packet; #endif - SubGhzSetting* setting; SubGhzLastSettings* last_settings; FuriString* error_str; @@ -133,33 +100,29 @@ struct SubGhz { bool in_decoder_scene; bool in_decoder_scene_skip; + bool ignore_starline; + bool ignore_auto_alarms; + bool ignore_magellan; + + SecureData* secure_data; + SubGhzDecodeRawState decode_raw_state; SubGhzFileEncoderWorker* decode_raw_file_worker_encoder; SubGhzThresholdRssi* threshold_rssi; SubGhzRxKeyState rx_key_state; + uint16_t idx_menu_chosen; + SubGhzLoadTypeFile load_type_file; + void* rpc_ctx; }; -void subghz_preset_init( - void* context, - const char* preset_name, - uint32_t frequency, - uint8_t* preset_data, - size_t preset_data_size); -bool subghz_set_preset(SubGhz* subghz, const char* preset); void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation); -void subghz_begin(SubGhz* subghz, uint8_t* preset_data); -uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); -void subghz_rx_end(SubGhz* subghz); -void subghz_sleep(SubGhz* subghz); void subghz_blink_start(SubGhz* instance); void subghz_blink_stop(SubGhz* instance); -bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); -void subghz_tx_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); @@ -167,27 +130,15 @@ bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, const char* dev_file_name); + +void subghz_save_to_file(void* context); + bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path); -uint32_t subghz_random_serial(void); -void subghz_hopper_update(SubGhz* subghz); -void subghz_speaker_on(SubGhz* subghz); -void subghz_speaker_off(SubGhz* subghz); -void subghz_speaker_mute(SubGhz* subghz); -void subghz_speaker_unmute(SubGhz* subghz); -void subghz_speaker_set_state(SubGhz* subghz, SubGhzSpeakerState state); -SubGhzSpeakerState subghz_speaker_get_state(SubGhz* subghz); - -void subghz_txrx_stop(SubGhz* subghz); -SubGhzTxRxState subghz_txrx_get_state(SubGhz* subghz); -SubGhzHopperState subghz_hopper_get_state(SubGhz* subghz); -void subghz_hopper_set_state(SubGhz* subghz, SubGhzHopperState state); -void subghz_hopper_remove_pause(SubGhz* subghz); -void subghz_subghz_hopper_set_pause(SubGhz* subghz); void subghz_lock(SubGhz* subghz); void subghz_unlock(SubGhz* subghz); @@ -198,87 +149,5 @@ SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); -//#############Create new Key############## -bool subghz_gen_data_protocol( - void* context, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit); - -bool subghz_gen_data_protocol_and_te( - SubGhz* subghz, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t te); - -bool subghz_scene_set_type_submenu_gen_data_keeloq( - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - bool nice_one); - -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt); - -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt); - -bool subghz_gen_secplus_v2_protocol( - SubGhz* subghz, - const char* name_preset, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint32_t cnt); - -bool subghz_gen_secplus_v1_protocol(SubGhz* subghz, const char* name_preset, uint32_t frequency); - extern const NotificationSequence subghz_sequence_rx; extern const NotificationSequence subghz_sequence_rx_locked; diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c new file mode 100644 index 000000000..d132eb9c1 --- /dev/null +++ b/applications/main/subghz/subghz_radio.c @@ -0,0 +1,723 @@ +#include "subghz_radio.h" + +#define TAG "SubGhz" + +void subghz_preset_init( + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(txrx); + furi_string_set(txrx->preset->name, preset_name); + txrx->preset->frequency = frequency; + txrx->preset->data = preset_data; + txrx->preset->data_size = preset_data_size; +} + +bool subghz_set_preset(SubGhzTxRx* txrx, const char* preset) { + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + furi_string_set(txrx->preset->name, "AM270"); + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + furi_string_set(txrx->preset->name, "AM650"); + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + furi_string_set(txrx->preset->name, "FM238"); + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + furi_string_set(txrx->preset->name, "FM476"); + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + furi_string_set(txrx->preset->name, "CUSTOM"); + } else { + FURI_LOG_E(TAG, "Unknown preset"); + return false; + } + return true; +} + +void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { + furi_assert(txrx); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + txrx->txrx_state = SubGhzTxRxStateIDLE; +} + +uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency) { + furi_assert(txrx); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert(txrx->txrx_state != SubGhzTxRxStateRx && txrx->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_speaker_on(txrx); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, txrx->worker); + subghz_worker_start(txrx->worker); + txrx->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_idle(SubGhzTxRx* txrx) { + furi_assert(txrx); + furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_speaker_off(txrx); + txrx->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_rx_end(SubGhzTxRx* txrx) { + furi_assert(txrx); + furi_assert(txrx->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(txrx->worker)) { + subghz_worker_stop(txrx->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_speaker_off(txrx); + txrx->txrx_state = SubGhzTxRxStateIDLE; +} + +// static void subghz_sleep(SubGhzTxRx* txrx) { +// furi_assert(txrx); +// furi_hal_subghz_sleep(); +// txrx->txrx_state = SubGhzTxRxStateSleep; +// } + +static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) { + furi_assert(txrx); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_speaker_on(txrx); + txrx->txrx_state = SubGhzTxRxStateTx; + } + return ret; +} + +bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { + furi_assert(txrx); + + bool ret = false; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, furi_string_get_cstr(temp_str)); + + if(txrx->transmitter) { + if(subghz_transmitter_deserialize(txrx->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(txrx->preset->name), "") != 0) { + subghz_begin( + txrx, + subghz_setting_get_preset_data_by_name( + txrx->setting, furi_string_get_cstr(txrx->preset->name))); + } else { + FURI_LOG_E( + TAG, + "Unknown name preset \" %s \"", + furi_string_get_cstr(txrx->preset->name)); + subghz_begin( + txrx, subghz_setting_get_preset_data_by_name(txrx->setting, "AM650")); + } + if(txrx->preset->frequency) { + ret = subghz_tx(txrx, txrx->preset->frequency); + } else { + ret = subghz_tx(txrx, 433920000); + } + if(ret) { + //Start TX + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, txrx->transmitter); + } else { + //Todo: Show error + //subghz_dialog_message_show_only_rx(subghz); + } + } else { + //Todo: Show error + // dialog_message_show_storage_error( + // dialogs, "Error in protocol\nparameters\ndescription"); + } + } + if(!ret) { + subghz_transmitter_free(txrx->transmitter); + if(txrx->txrx_state != SubGhzTxRxStateSleep) { + subghz_idle(txrx); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_need_save_callback_set( + SubGhzTxRx* txrx, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(txrx); + txrx->need_save_callback = callback; + txrx->need_save_context = context; +} + +static void subghz_tx_stop(SubGhzTxRx* txrx) { + furi_assert(txrx); + furi_assert(txrx->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(txrx->transmitter); + subghz_transmitter_free(txrx->transmitter); + + //if protocol dynamic then we save the last upload + if(txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(txrx->need_save_callback) { + txrx->need_save_callback(txrx->need_save_context); + } + } + subghz_idle(txrx); + subghz_speaker_off(txrx); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* txrx) { + furi_assert(txrx); + + switch(txrx->txrx_state) { + case SubGhzTxRxStateTx: + subghz_tx_stop(txrx); + subghz_speaker_unmute(txrx); + //subghz_sleep(txrx); + break; + case SubGhzTxRxStateRx: + subghz_rx_end(txrx); + subghz_speaker_mute(txrx); + //subghz_sleep(txrx); + break; + + default: + break; + } +} + +SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->txrx_state; +} + +void subghz_hopper_update(SubGhzTxRx* txrx) { + furi_assert(txrx); + + switch(txrx->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(txrx->hopper_timeout != 0) { + txrx->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + txrx->hopper_timeout = 10; + txrx->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + txrx->hopper_state = SubGhzHopperStateRunning; + } + // Select next frequency + if(txrx->hopper_idx_frequency < subghz_setting_get_hopper_frequency_count(txrx->setting) - 1) { + txrx->hopper_idx_frequency++; + } else { + txrx->hopper_idx_frequency = 0; + } + + if(txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(txrx); + }; + if(txrx->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(txrx->receiver); + txrx->preset->frequency = + subghz_setting_get_hopper_frequency(txrx->setting, txrx->hopper_idx_frequency); + subghz_rx(txrx, txrx->preset->frequency); + } +} + +SubGhzHopperState subghz_hopper_get_state(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->hopper_state; +} + +void subghz_hopper_set_state(SubGhzTxRx* txrx, SubGhzHopperState state) { + furi_assert(txrx); + txrx->hopper_state = state; +} + +void subghz_hopper_remove_pause(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->hopper_state == SubGhzHopperStatePause) { + txrx->hopper_state = SubGhzHopperStateRunning; + } +} + +void subghz_subghz_hopper_set_pause(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->hopper_state == SubGhzHopperStateRunning) { + txrx->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_speaker_on(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + + if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + if(!txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } else { + txrx->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_speaker_off(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(txrx->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + if(!txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + furi_hal_speaker_release(); + if(txrx->speaker_state == SubGhzSpeakerStateShutdown) + txrx->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_speaker_mute(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } + } +} + +void subghz_speaker_unmute(SubGhzTxRx* txrx) { + furi_assert(txrx); + if(txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } + } +} + +void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state) { + furi_assert(txrx); + txrx->speaker_state = state; +} + +SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->speaker_state; +} + +//#############Create new Key############## +#include +#include +#include +#include +#include + +#include +#include +#include + +bool subghz_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhzTxRx* txrx = context; + + bool res = false; + + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + txrx->decoder_result = + subghz_receiver_search_decoder_base_by_name(txrx->receiver, protocol_name); + + if(txrx->decoder_result == NULL) { + //TODO: Error + // furi_string_set(error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(txrx->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + txrx->decoder_result, txrx->fff_data, txrx->preset) != SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(txrx->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_gen_data_protocol_and_te( + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(txrx); + bool ret = false; + if(subghz_gen_data_protocol(txrx, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(txrx->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name) { + furi_assert(txrx); + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + manufacture_name, + txrx->preset)) { + flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", manufacture_name); + res = true; + } + subghz_transmitter_free(txrx->transmitter); + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", "BFT"); + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset, + nice_one)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_faac_slh_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); + subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_somfy_telis_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_gen_secplus_v2_protocol( + SubGhzTxRx* txrx, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(txrx); + + bool ret = false; + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_preset_init(txrx, name_preset, frequency, NULL, 0); + if(txrx->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset); + ret = true; + } + return ret; +} + +bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency) { + furi_assert(txrx); + + bool ret = false; + uint32_t serial = (uint32_t)rand(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = (uint32_t)rand(); + } + if(subghz_gen_data_protocol( + txrx, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; +} \ No newline at end of file diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h new file mode 100644 index 000000000..d0e9f5c87 --- /dev/null +++ b/applications/main/subghz/subghz_radio.h @@ -0,0 +1,160 @@ +#pragma once +//#include "subghz_i.h" +#include "helpers/subghz_types.h" +#include +#include +#include +#include + +#include "subghz_history.h" + +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolFlag filter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzHistory* history; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; + + bool debug_pin_state; +}; + +typedef struct SubGhzTxRx SubGhzTxRx; + +void subghz_preset_init( + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size); + +bool subghz_set_preset(SubGhzTxRx* txrx, const char* preset); +void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data); +uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency); +bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format); +//void subghz_rx_end(SubGhzTxRx* txrx); //depricated +//void subghz_sleep(SubGhzTxRx* txrx); + +void subghz_txrx_stop(SubGhzTxRx* txrx); +SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx); + +void subghz_hopper_update(SubGhzTxRx* txrx); +SubGhzHopperState subghz_hopper_get_state(SubGhzTxRx* txrx); +void subghz_hopper_set_state(SubGhzTxRx* txrx, SubGhzHopperState state); +void subghz_hopper_remove_pause(SubGhzTxRx* txrx); +void subghz_subghz_hopper_set_pause(SubGhzTxRx* txrx); + +void subghz_speaker_on(SubGhzTxRx* txrx); +void subghz_speaker_off(SubGhzTxRx* txrx); +void subghz_speaker_mute(SubGhzTxRx* txrx); +void subghz_speaker_unmute(SubGhzTxRx* txrx); +void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state); +SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx); + +void subghz_txrx_need_save_callback_set( + SubGhzTxRx* txrx, + SubGhzTxRxNeedSaveCallback callback, + void* context); +FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx); +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx); + +//#############Create new Key############## +bool subghz_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +bool subghz_gen_data_protocol_and_te( + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +bool subghz_scene_set_type_submenu_gen_data_keeloq( + SubGhzTxRx* txrx, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one); + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_gen_secplus_v2_protocol( + SubGhzTxRx* txrx, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency); \ No newline at end of file From f71900694b91065b63ccada55d4ac58edf82d275 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 13:34:54 +0300 Subject: [PATCH 159/216] SubGhz: refactoring --- .../subghz/scenes/subghz_scene_decode_raw.c | 2 +- .../main/subghz/scenes/subghz_scene_delete.c | 4 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 23 ++++---- .../subghz/scenes/subghz_scene_receiver.c | 47 +++++++-------- .../scenes/subghz_scene_receiver_info.c | 13 ++--- .../subghz/scenes/subghz_scene_transmitter.c | 9 +-- applications/main/subghz/subghz_i.c | 38 ++++--------- applications/main/subghz/subghz_i.h | 2 - applications/main/subghz/subghz_radio.c | 57 ++++++++++++++++--- applications/main/subghz/subghz_radio.h | 9 ++- 11 files changed, 113 insertions(+), 93 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 955e0df89..6075cd655 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -29,7 +29,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 4cad14bbf..cf0bdefb1 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -15,7 +15,7 @@ void subghz_scene_delete_on_enter(void* context) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, @@ -33,7 +33,7 @@ void subghz_scene_delete_on_enter(void* context) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index ee7983dfd..ed960d666 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -30,7 +30,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 9abc24523..7879682a2 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -41,10 +41,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME - subghz_get_frequency_modulation(subghz, frequency_str, NULL); - furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, true); + //furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); #else - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); #endif subghz_read_raw_add_data_statusbar( subghz->subghz_read_raw, @@ -113,9 +113,7 @@ void subghz_scene_read_raw_on_enter(void* context) { //set callback view raw subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME)); //set filter RAW feed subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); @@ -131,7 +129,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); //Stop save file subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || @@ -255,10 +253,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWIDLE: subghz_txrx_stop(subghz->txrx); size_t spl_count = subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); FuriString* temp_str = furi_string_alloc(); furi_string_printf( @@ -284,7 +282,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { if(subghz_protocol_raw_save_to_file_init( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), RAW_FILE_NAME, subghz->txrx->preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); @@ -333,14 +331,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_update_sample_write( subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx))); SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); subghz_read_raw_add_data_rssi( subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, !ret_rssi.is_above); + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), + !ret_rssi.is_above); break; case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 766810a04..bd0b971b4 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -46,17 +46,20 @@ static void subghz_scene_receiver_update_statusbar(void* context) { #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->txrx->history) > 0) { - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); } else { - subghz_get_frequency_modulation(subghz, frequency_str, NULL); + FuriString* temp_str = furi_string_alloc(); + + subghz_get_frequency_modulation(subghz->txrx, frequency_str, temp_str, true); furi_string_printf( modulation_str, "%s Mod: %s", furi_hal_subghz_get_radio_type() ? "Ext" : "Int", - furi_string_get_cstr(subghz->txrx->preset->name)); + furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); } #else - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); #endif subghz_view_receiver_add_data_statusbar( @@ -155,37 +158,26 @@ void subghz_scene_receiver_on_enter(void* context) { // TODO: Replace with proper solution based on protocol flags, remove kostily and velosipedy from here // Needs to be done after subghz refactoring merge!!! if(subghz->ignore_starline == true) { - SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; - protocoldecoderbase = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Star Line"); - if(protocoldecoderbase) { + if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Star Line")) { subghz_protocol_decoder_base_set_decoder_callback( - protocoldecoderbase, NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); } } if(subghz->ignore_auto_alarms == true) { - SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; - protocoldecoderbase = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "KIA Seed"); - if(protocoldecoderbase) { + if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "KIA Seed")) { subghz_protocol_decoder_base_set_decoder_callback( - protocoldecoderbase, NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); } - protocoldecoderbase = NULL; - protocoldecoderbase = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Scher-Khan"); - if(protocoldecoderbase) { + + if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Scher-Khan")) { subghz_protocol_decoder_base_set_decoder_callback( - protocoldecoderbase, NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); } } if(subghz->ignore_magellan == true) { - SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; - protocoldecoderbase = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Magellan"); - if(protocoldecoderbase) { + if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Magellan")) { subghz_protocol_decoder_base_set_decoder_callback( - protocoldecoderbase, NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); } } @@ -199,9 +191,8 @@ void subghz_scene_receiver_on_enter(void* context) { subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); - furi_assert(subghz->txrx->decoder_result); + furi_check( + subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME)); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); } @@ -277,7 +268,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( - (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, ret_rssi.rssi); + (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi); switch(subghz->state_notifications) { case SubGhzNotificationStateRx: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 3c53ac021..ed9f06770 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -23,14 +23,13 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhz* subghz = context; - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->idx_menu_chosen)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, + subghz_history_get_protocol_name(subghz->txrx->history, subghz->idx_menu_chosen))) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, + subghz_txrx_get_decoder(subghz->txrx), subghz_history_get_raw_data(subghz->txrx->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = @@ -53,7 +52,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, @@ -71,7 +70,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { AlignTop, FontSecondary, furi_string_get_cstr(modulation_str)); - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); + subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text); widget_add_string_multiline_element( subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text)); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 375c142d1..c75a1b6b3 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -15,7 +15,7 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; - if(subghz->txrx->decoder_result) { + if(subghz_txrx_get_decoder(subghz->txrx)) { FuriString* key_str = furi_string_alloc(); FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); @@ -23,16 +23,17 @@ bool subghz_scene_transmitter_update_data_show(void* context) { bool show_button = false; if(subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz_txtx_get_fff_data(subghz->txrx)) == + subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { - subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); + subghz_protocol_decoder_base_get_string( + subghz_txrx_get_decoder(subghz->txrx), key_str); if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) { show_button = true; } - subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 3b9c1c695..db8bc5cf2 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,20 +18,6 @@ #define TAG "SubGhz" -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) { - furi_assert(subghz); - if(frequency != NULL) { - furi_string_printf( - frequency, - "%03ld.%02ld", - subghz->txrx->preset->frequency / 1000000 % 1000, - subghz->txrx->preset->frequency / 10000 % 100); - } - if(modulation != NULL) { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name)); - } -} - void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); @@ -97,7 +83,6 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { load_key_state = SubGhzLoadKeyStateOnlyRx; break; } - //subghz->txrx->preset->frequency = temp_data32; //Load preset if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { @@ -105,31 +90,31 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - if(!subghz_set_preset(subghz->txrx, furi_string_get_cstr(temp_str))) { + furi_string_set_str( + temp_str, subghz_set_preset(subghz->txrx, furi_string_get_cstr(temp_str))); + if(temp_str == NULL) { break; } - if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { //Todo add Custom_preset_module //delete preset if it already exists subghz_setting_delete_custom_preset( - subghz_txrx_get_setting(subghz->txrx), - furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); //load custom preset from file if(!subghz_setting_load_custom_preset( subghz_txrx_get_setting(subghz->txrx), - furi_string_get_cstr(subghz->txrx->preset->name), + furi_string_get_cstr(temp_str), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); break; } } size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz_txrx_get_setting(subghz->txrx), - furi_string_get_cstr(subghz->txrx->preset->name)); + subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); subghz_preset_init( subghz->txrx, - furi_string_get_cstr(subghz->txrx->preset->name), + furi_string_get_cstr(temp_str), temp_data32, subghz_setting_get_preset_data(subghz_txrx_get_setting(subghz->txrx), preset_index), subghz_setting_get_preset_data_size( @@ -151,11 +136,10 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx))); } - subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, furi_string_get_cstr(temp_str)); - if(subghz->txrx->decoder_result) { + if(subghz_txrx_load_decoder_by_name_protocol( + subghz->txrx, furi_string_get_cstr(temp_str))) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz->txrx->decoder_result, subghz_txtx_get_fff_data(subghz->txrx)); + subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx)); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 965538d81..58d715d8b 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -118,8 +118,6 @@ struct SubGhz { void* rpc_ctx; }; -void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation); - void subghz_blink_start(SubGhz* instance); void subghz_blink_stop(SubGhz* instance); diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index d132eb9c1..4a45479b6 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -15,22 +15,45 @@ void subghz_preset_init( txrx->preset->data_size = preset_data_size; } -bool subghz_set_preset(SubGhzTxRx* txrx, const char* preset) { +void subghz_get_frequency_modulation( + SubGhzTxRx* txrx, + FuriString* frequency, + FuriString* modulation, + bool long_name) { + furi_assert(txrx); + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + txrx->preset->frequency / 1000000 % 1000, + txrx->preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + if(long_name) { + furi_string_printf(modulation, "%s", furi_string_get_cstr(txrx->preset->name)); + } else { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(txrx->preset->name)); + } + } +} + +const char* subghz_set_preset(SubGhzTxRx* txrx, const char* preset) { + UNUSED(txrx); + const char* preset_name = NULL; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - furi_string_set(txrx->preset->name, "AM270"); + preset_name = "AM270"; } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - furi_string_set(txrx->preset->name, "AM650"); + preset_name = "AM650"; } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - furi_string_set(txrx->preset->name, "FM238"); + preset_name = "FM238"; } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - furi_string_set(txrx->preset->name, "FM476"); + preset_name = "FM476"; } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - furi_string_set(txrx->preset->name, "CUSTOM"); + preset_name = "CUSTOM"; } else { FURI_LOG_E(TAG, "Unknown preset"); - return false; } - return true; + return preset_name; } void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { @@ -385,6 +408,24 @@ SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx) { return txrx->speaker_state; } +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* txrx, const char* name_protocol) { + furi_assert(txrx); + furi_assert(name_protocol); + bool res = false; + txrx->decoder_result = NULL; + txrx->decoder_result = + subghz_receiver_search_decoder_base_by_name(txrx->receiver, name_protocol); + if(txrx->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->decoder_result; +} + //#############Create new Key############## #include #include diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index d0e9f5c87..579f992a0 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -47,7 +47,12 @@ void subghz_preset_init( uint8_t* preset_data, size_t preset_data_size); -bool subghz_set_preset(SubGhzTxRx* txrx, const char* preset); +const char* subghz_set_preset(SubGhzTxRx* txrx, const char* preset); +void subghz_get_frequency_modulation( + SubGhzTxRx* txrx, + FuriString* frequency, + FuriString* modulation, + bool long_name); void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data); uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency); bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format); @@ -69,6 +74,8 @@ void subghz_speaker_mute(SubGhzTxRx* txrx); void subghz_speaker_unmute(SubGhzTxRx* txrx); void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state); SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx); +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* txrx, const char* name_protocol); +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx); void subghz_txrx_need_save_callback_set( SubGhzTxRx* txrx, From 07203f09893e24723d3f018bbb7bce32c54f284d Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 15:11:54 +0300 Subject: [PATCH 160/216] SubGhz: refactoring --- .../subghz_frequency_analyzer_worker.c | 2 +- .../subghz/scenes/subghz_scene_decode_raw.c | 23 ++--- .../subghz/scenes/subghz_scene_need_saving.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 19 ++-- .../subghz/scenes/subghz_scene_receiver.c | 37 ++++--- .../scenes/subghz_scene_receiver_config.c | 96 ++++++++++++------- .../scenes/subghz_scene_receiver_info.c | 25 ++--- .../subghz/scenes/subghz_scene_save_name.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- applications/main/subghz/subghz.c | 10 +- applications/main/subghz/subghz_i.c | 4 +- applications/main/subghz/subghz_i.h | 1 + applications/main/subghz/subghz_radio.c | 52 ++++++---- applications/main/subghz/subghz_radio.h | 14 +-- 14 files changed, 162 insertions(+), 127 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 34f7e8cff..6fec29565 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -278,7 +278,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); SubGhz* subghz = context; - instance->setting = subghz->txrx->setting; + instance->setting = subghz_txrx_get_setting(subghz->txrx); instance->trigger_level = subghz->last_settings->frequency_analyzer_trigger; //instance->trigger_level = SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD; return instance; diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 6075cd655..e75f6fda6 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -25,7 +25,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; FuriString* history_stat_str = furi_string_alloc(); - if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { + if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); @@ -60,21 +60,22 @@ static void subghz_scene_add_to_history_callback( SubGhz* subghz = context; FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - uint16_t idx = subghz_history_get_item(subghz->txrx->history); + uint16_t idx = subghz_history_get_item(subghz->history); + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); - if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + if(subghz_history_add_to_history(subghz->history, decoder_base, &preset)) { furi_string_reset(item_name); furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); - subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); + subghz_history_get_text_item_menu(subghz->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->history, item_time, idx); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->txrx->history, idx)); + subghz_history_get_type_protocol(subghz->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } @@ -173,7 +174,7 @@ void subghz_scene_decode_raw_on_enter(void* context) { if(subghz->decode_raw_state == SubGhzDecodeRawStateStart) { //Decode RAW to history - subghz_history_reset(subghz->txrx->history); + subghz_history_reset(subghz->history); if(subghz_scene_decode_raw_start(subghz)) { subghz->decode_raw_state = SubGhzDecodeRawStateLoading; subghz->state_notifications = SubGhzNotificationStateRx; @@ -181,16 +182,16 @@ void subghz_scene_decode_raw_on_enter(void* context) { } else { //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(subghz->history); i++) { furi_string_reset(item_name); furi_string_reset(item_time); - subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); - subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); + subghz_history_get_text_item_menu(subghz->history, item_name, i); + subghz_history_get_time_item_menu(subghz->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->txrx->history, i)); + subghz_history_get_type_protocol(subghz->history, i)); } furi_string_free(item_name); furi_string_free(item_time); diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index e64f75ef7..b0fc70b8b 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -48,7 +48,7 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneExit) { if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateExit) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_preset_init( + subghz_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 7879682a2..4fed9424c 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -42,6 +42,7 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { #ifdef SUBGHZ_EXT_PRESET_NAME subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, true); + //TODO if need subghz_get_preset //furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); #else subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); @@ -139,14 +140,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { //Restore default setting if(subghz->raw_send_only) { - subghz_preset_init( + subghz_set_preset( subghz->txrx, "AM650", - subghz_setting_get_default_frequency(subghz->txrx->setting), + subghz_setting_get_default_frequency( + subghz_txrx_get_setting(subghz->txrx)), NULL, 0); } else { - subghz_preset_init( + subghz_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } if(!scene_manager_search_and_switch_to_previous_scene( @@ -281,18 +283,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); if(subghz_protocol_raw_save_to_file_init( (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), RAW_FILE_NAME, - subghz->txrx->preset)) { + &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - subghz_txrx_stop(subghz->txrx); - subghz_begin( - subghz->txrx, - subghz_setting_get_preset_data_by_name( - subghz->txrx->setting, - furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index bd0b971b4..72083fdeb 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -40,12 +40,12 @@ const NotificationSequence subghz_sequence_rx_locked = { static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; FuriString* history_stat_str = furi_string_alloc(); - if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { + if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME - if(subghz_history_get_last_index(subghz->txrx->history) > 0) { + if(subghz_history_get_last_index(subghz->history) > 0) { subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); } else { FuriString* temp_str = furi_string_alloc(); @@ -94,21 +94,22 @@ static void subghz_scene_add_to_history_callback( FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - uint16_t idx = subghz_history_get_item(subghz->txrx->history); + uint16_t idx = subghz_history_get_item(subghz->history); - if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + if(subghz_history_add_to_history(subghz->history, decoder_base, &preset)) { furi_string_reset(item_name); furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); - subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); + subghz_history_get_text_item_menu(subghz->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->history, item_time, idx); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->txrx->history, idx)); + subghz_history_get_type_protocol(subghz->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } @@ -125,8 +126,8 @@ void subghz_scene_receiver_on_enter(void* context) { FuriString* item_time = furi_string_alloc(); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { - subghz_preset_init(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); - subghz_history_reset(subghz->txrx->history); + subghz_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_history_reset(subghz->history); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } @@ -135,16 +136,16 @@ void subghz_scene_receiver_on_enter(void* context) { //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(subghz->history); i++) { furi_string_reset(item_name); furi_string_reset(item_time); - subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); - subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); + subghz_history_get_text_item_menu(subghz->history, item_name, i); + subghz_history_get_time_item_menu(subghz->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->txrx->history, i)); + subghz_history_get_type_protocol(subghz->history, i)); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(item_name); @@ -183,11 +184,7 @@ void subghz_scene_receiver_on_enter(void* context) { subghz->state_notifications = SubGhzNotificationStateRx; subghz_txrx_stop(subghz->txrx); - subghz_begin( - subghz->txrx, - subghz_setting_get_preset_data_by_name( - subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_rx_start(subghz->txrx); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it @@ -215,7 +212,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_preset_init( + subghz_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); @@ -232,7 +229,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverDeleteItem: subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); - subghz_history_delete_item(subghz->txrx->history, subghz->idx_menu_chosen); + subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen); subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); subghz_scene_receiver_update_statusbar(subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index f677739fd..752b26197 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -93,12 +93,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->txrx->setting); i++) { - if(value == subghz_setting_get_frequency(subghz->txrx->setting, i)) { + for(uint8_t i = 0; + i < subghz_setting_get_frequency_count(subghz_txrx_get_setting(subghz->txrx)); + i++) { + if(value == subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), i)) { index = i; break; } else { - index = subghz_setting_get_frequency_default_index(subghz->txrx->setting); + index = + subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); } } return index; @@ -108,12 +111,15 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->txrx->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->txrx->setting, i), preset_name)) { + for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz_txrx_get_setting(subghz->txrx)); + i++) { + if(!strcmp( + subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), i), + preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz->txrx->setting); + // index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); } } return index; @@ -149,33 +155,48 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->txrx->setting, index) / 1000000, - (subghz_setting_get_frequency(subghz->txrx->setting, index) % 1000000) / 10000); + subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index) / 1000000, + (subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index) % + 1000000) / + 10000); variable_item_set_current_value_text(item, text_buf); - subghz->txrx->preset->frequency = - subghz_setting_get_frequency(subghz->txrx->setting, index); - subghz->last_settings->frequency = subghz->txrx->preset->frequency; + + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + + subghz_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index), + preset.data, + preset.data_size); + + preset = subghz_get_preset(subghz->txrx); + + subghz->last_settings->frequency = preset.frequency; subghz_setting_set_default_frequency( - subghz->txrx->setting, subghz->txrx->preset->frequency); + subghz_txrx_get_setting(subghz->txrx), preset.frequency); } else { variable_item_set_current_value_index( - item, subghz_setting_get_frequency_default_index(subghz->txrx->setting)); + item, + subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); } } static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - const char* preset_name = subghz_setting_get_preset_name(subghz->txrx->setting, index); + const char* preset_name = + subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), index); variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); - subghz_preset_init( + subghz_set_preset( subghz->txrx, preset_name, - subghz->txrx->preset->frequency, - subghz_setting_get_preset_data(subghz->txrx->setting, index), - subghz_setting_get_preset_data_size(subghz->txrx->setting, index)); + preset.frequency, + subghz_setting_get_preset_data(subghz_txrx_get_setting(subghz->txrx), index), + subghz_setting_get_preset_data_size(subghz_txrx_get_setting(subghz->txrx), index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { @@ -189,18 +210,25 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->txrx->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->txrx->setting) % 1000000) / 10000); + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)) / 1000000, + (subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)) % + 1000000) / + 10000); variable_item_set_current_value_text( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), text_buf); - subghz->txrx->preset->frequency = - subghz_setting_get_default_frequency(subghz->txrx->setting); + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + subghz_set_preset( + subghz->txrx, + furi_string_get_cstr(preset.name), + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + preset.data, + preset.data_size); variable_item_set_current_value_index( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->txrx->setting)); + subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); } else { variable_item_set_current_value_text( (VariableItem*)scene_manager_get_scene_state( @@ -209,7 +237,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) variable_item_set_current_value_index( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->txrx->setting)); + subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); } subghz_hopper_set_state(subghz->txrx, hopping_value[index]); @@ -277,15 +305,15 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; + SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz->txrx->setting), + subghz_setting_get_frequency_count(subghz_txrx_get_setting(subghz->txrx)), subghz_scene_receiver_config_set_frequency, subghz); - value_index = - subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz); + value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); variable_item_set_current_value_index(item, value_index); @@ -294,21 +322,23 @@ void subghz_scene_receiver_config_on_enter(void* context) { text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz->txrx->setting, value_index) / 1000000, - (subghz_setting_get_frequency(subghz->txrx->setting, value_index) % 1000000) / 10000); + subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), value_index) / 1000000, + (subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), value_index) % + 1000000) / + 10000); variable_item_set_current_value_text(item, text_buf); item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz->txrx->setting), + subghz_setting_get_preset_count(subghz_txrx_get_setting(subghz->txrx)), subghz_scene_receiver_config_set_preset, subghz); - value_index = subghz_scene_receiver_config_next_preset( - furi_string_get_cstr(subghz->txrx->preset->name), subghz); + value_index = + subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz->txrx->setting, value_index)); + item, subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index ed9f06770..a026371fd 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -26,15 +26,15 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { if(subghz_txrx_load_decoder_by_name_protocol( subghz->txrx, - subghz_history_get_protocol_name(subghz->txrx->history, subghz->idx_menu_chosen))) { + subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) { //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal subghz_protocol_decoder_base_deserialize( subghz_txrx_get_decoder(subghz->txrx), - subghz_history_get_raw_data(subghz->txrx->history, subghz->idx_menu_chosen)); + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen)); SubGhzRadioPreset* preset = - subghz_history_get_radio_preset(subghz->txrx->history, subghz->idx_menu_chosen); - subghz_preset_init( + subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); + subghz_set_preset( subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, @@ -123,21 +123,14 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) //CC1101 Stop RX -> Start TX subghz_subghz_hopper_set_pause(subghz->txrx); - subghz_txrx_stop(subghz->txrx); - if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } if(!subghz_tx_start( subghz->txrx, - subghz_history_get_raw_data(subghz->txrx->history, subghz->idx_menu_chosen))) { - subghz_txrx_stop(subghz->txrx); - subghz_begin( - subghz->txrx, - subghz_setting_get_preset_data_by_name( - subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { + subghz_rx_start(subghz->txrx); subghz_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } else { @@ -153,11 +146,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_txrx_stop(subghz->txrx); if(!subghz->in_decoder_scene) { - subghz_begin( - subghz->txrx, - subghz_setting_get_preset_data_by_name( - subghz->txrx->setting, furi_string_get_cstr(subghz->txrx->preset->name))); - subghz_rx(subghz->txrx, subghz->txrx->preset->frequency); + subghz_rx_start(subghz->txrx); subghz_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index f31d4be79..ca48d6b45 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -156,7 +156,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { subghz_save_protocol_to_file( subghz, subghz_history_get_raw_data( - subghz->txrx->history, subghz->idx_menu_chosen), + subghz->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index c75a1b6b3..5c4d03403 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -72,7 +72,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(subghz->txrx); + if(subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 8731bbc9d..be3df0551 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -272,9 +272,9 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); subghz->txrx->preset->name = furi_string_alloc(); if(!alloc_for_tx_only) { - subghz_preset_init(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } else { - subghz_preset_init( + subghz_set_preset( subghz->txrx, "AM650", subghz_setting_get_default_frequency(subghz->txrx->setting), @@ -287,7 +287,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); subghz->txrx->debug_pin_state = false; if(!alloc_for_tx_only) { - subghz->txrx->history = subghz_history_alloc(); + subghz->history = subghz_history_alloc(); } subghz->txrx->worker = subghz_worker_alloc(); @@ -333,6 +333,8 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { } subghz_speaker_off(subghz->txrx); + subghz_txrx_stop(subghz->txrx); + subghz_sleep(subghz->txrx); #if FURI_DEBUG // Packet Test @@ -421,7 +423,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { flipper_format_free(subghz->txrx->fff_data); if(!alloc_for_tx_only) { - subghz_history_free(subghz->txrx->history); + subghz_history_free(subghz->history); } furi_string_free(subghz->txrx->preset->name); free(subghz->txrx->preset); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index db8bc5cf2..25e81725b 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -91,7 +91,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } furi_string_set_str( - temp_str, subghz_set_preset(subghz->txrx, furi_string_get_cstr(temp_str))); + temp_str, subghz_get_name_preset(subghz->txrx, furi_string_get_cstr(temp_str))); if(temp_str == NULL) { break; } @@ -112,7 +112,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } size_t preset_index = subghz_setting_get_inx_preset_by_name( subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); - subghz_preset_init( + subghz_set_preset( subghz->txrx, furi_string_get_cstr(temp_str), temp_data32, diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 58d715d8b..0914d12ed 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -111,6 +111,7 @@ struct SubGhz { SubGhzThresholdRssi* threshold_rssi; SubGhzRxKeyState rx_key_state; + SubGhzHistory* history; uint16_t idx_menu_chosen; SubGhzLoadTypeFile load_type_file; diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index 4a45479b6..ed3215ebc 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -2,7 +2,7 @@ #define TAG "SubGhz" -void subghz_preset_init( +void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, uint32_t frequency, @@ -37,7 +37,7 @@ void subghz_get_frequency_modulation( } } -const char* subghz_set_preset(SubGhzTxRx* txrx, const char* preset) { +const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset) { UNUSED(txrx); const char* preset_name = NULL; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { @@ -56,7 +56,12 @@ const char* subghz_set_preset(SubGhzTxRx* txrx, const char* preset) { return preset_name; } -void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { +SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx) { + furi_assert(txrx); + return *txrx->preset; +} + +static void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { furi_assert(txrx); furi_hal_subghz_reset(); furi_hal_subghz_idle(); @@ -65,7 +70,7 @@ void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { txrx->txrx_state = SubGhzTxRxStateIDLE; } -uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency) { +static uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency) { furi_assert(txrx); if(!furi_hal_subghz_is_frequency_valid(frequency)) { furi_crash("SubGhz: Incorrect RX frequency."); @@ -106,11 +111,11 @@ static void subghz_rx_end(SubGhzTxRx* txrx) { txrx->txrx_state = SubGhzTxRxStateIDLE; } -// static void subghz_sleep(SubGhzTxRx* txrx) { -// furi_assert(txrx); -// furi_hal_subghz_sleep(); -// txrx->txrx_state = SubGhzTxRxStateSleep; -// } +void subghz_sleep(SubGhzTxRx* txrx) { + furi_assert(txrx); + furi_hal_subghz_sleep(); + txrx->txrx_state = SubGhzTxRxStateSleep; +} static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) { furi_assert(txrx); @@ -133,6 +138,9 @@ static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) { bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { furi_assert(txrx); + furi_assert(flipper_format); + + subghz_txrx_stop(txrx); bool ret = false; FuriString* temp_str = furi_string_alloc(); @@ -200,6 +208,16 @@ bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { return ret; } +void subghz_rx_start(SubGhzTxRx* txrx) { + furi_assert(txrx); + subghz_txrx_stop(txrx); + subghz_begin( + txrx, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(txrx), furi_string_get_cstr(txrx->preset->name))); + subghz_rx(txrx, txrx->preset->frequency); +} + void subghz_txrx_need_save_callback_set( SubGhzTxRx* txrx, SubGhzTxRxNeedSaveCallback callback, @@ -449,7 +467,7 @@ bool subghz_gen_data_protocol( bool res = false; - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(txrx->receiver, protocol_name); @@ -520,7 +538,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_keeloq_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -552,7 +570,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -596,7 +614,7 @@ bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -629,7 +647,7 @@ bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_faac_slh_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -670,7 +688,7 @@ bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -700,7 +718,7 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); - subghz_preset_init(txrx, preset_name, frequency, NULL, 0); + subghz_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_somfy_telis_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -729,7 +747,7 @@ bool subghz_gen_secplus_v2_protocol( bool ret = false; txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_preset_init(txrx, name_preset, frequency, NULL, 0); + subghz_set_preset(txrx, name_preset, frequency, NULL, 0); if(txrx->transmitter) { subghz_protocol_secplus_v2_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 579f992a0..9a9f90d3d 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -21,7 +21,6 @@ struct SubGhzTxRx { FlipperFormat* fff_data; SubGhzRadioPreset* preset; - SubGhzHistory* history; SubGhzSetting* setting; uint8_t hopper_timeout; @@ -40,26 +39,27 @@ struct SubGhzTxRx { typedef struct SubGhzTxRx SubGhzTxRx; -void subghz_preset_init( +void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, uint32_t frequency, uint8_t* preset_data, size_t preset_data_size); -const char* subghz_set_preset(SubGhzTxRx* txrx, const char* preset); +const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset); +SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx); + void subghz_get_frequency_modulation( SubGhzTxRx* txrx, FuriString* frequency, FuriString* modulation, bool long_name); -void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data); -uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency); bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format); //void subghz_rx_end(SubGhzTxRx* txrx); //depricated -//void subghz_sleep(SubGhzTxRx* txrx); - +void subghz_rx_start(SubGhzTxRx* txrx); void subghz_txrx_stop(SubGhzTxRx* txrx); +void subghz_sleep(SubGhzTxRx* txrx); + SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx); void subghz_hopper_update(SubGhzTxRx* txrx); From 076f6785cb517d025edd75a0b321817de88780c6 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 15:22:08 +0300 Subject: [PATCH 161/216] SubGhz: refactoring --- .../scenes/subghz_scene_receiver_info.c | 10 +++------ .../subghz/scenes/subghz_scene_transmitter.c | 9 +------- applications/main/subghz/subghz_radio.c | 22 +++++++++++++++++++ applications/main/subghz/subghz_radio.h | 3 +++ 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index a026371fd..f3cfd0962 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -78,8 +78,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { furi_string_free(modulation_str); furi_string_free(text); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_preserved(subghz->txrx)) { widget_add_button_element( subghz->widget, GuiButtonTypeRight, @@ -88,9 +87,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { subghz); } // Removed static check - if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - subghz->txrx->decoder_result->protocol->encoder->deserialize) { + if(subghz_txrx_protocol_is_send(subghz->txrx, false)) { widget_add_button_element( subghz->widget, GuiButtonTypeCenter, @@ -162,8 +159,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return false; } - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == - SubGhzProtocolFlag_Save) { + if(subghz_txrx_protocol_is_preserved(subghz->txrx)) { subghz_file_name_clear(subghz); if(subghz->in_decoder_scene) { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 5c4d03403..d5bd45618 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -20,26 +20,19 @@ bool subghz_scene_transmitter_update_data_show(void* context) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); - bool show_button = false; - if(subghz_protocol_decoder_base_deserialize( subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { subghz_protocol_decoder_base_get_string( subghz_txrx_get_decoder(subghz->txrx), key_str); - if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) { - show_button = true; - } - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), - show_button); + subghz_txrx_protocol_is_send(subghz->txrx, false)); ret = true; } furi_string_free(frequency_str); diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index ed3215ebc..cd556efce 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -444,6 +444,28 @@ SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx) { return txrx->decoder_result; } +bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* txrx) { + furi_assert(txrx); + return ( + (txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type) { + furi_assert(txrx); + if(check_type) { + return ( + ((txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == + SubGhzProtocolFlag_Send) && + txrx->decoder_result->protocol->encoder->deserialize && + txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == + SubGhzProtocolFlag_Send) && + txrx->decoder_result->protocol->encoder->deserialize); +} + //#############Create new Key############## #include #include diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 9a9f90d3d..0a51334cb 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -84,6 +84,9 @@ void subghz_txrx_need_save_callback_set( FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx); SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx); +bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* txrx); +bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type); + //#############Create new Key############## bool subghz_gen_data_protocol( void* context, From 4cbdbd9ef5b0bc6500f59ccf80095cbae7adad6a Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 15:58:56 +0300 Subject: [PATCH 162/216] SubGhz: refactoring --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 2 +- applications/main/subghz/scenes/subghz_scene_read_raw.c | 4 ++-- .../main/subghz/scenes/subghz_scene_receiver_config.c | 6 +++--- applications/main/subghz/subghz.c | 5 +++-- applications/main/subghz/subghz_i.h | 1 + applications/main/subghz/subghz_radio.c | 5 +++++ applications/main/subghz/subghz_radio.h | 3 ++- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index e75f6fda6..fa3082a3f 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -170,7 +170,7 @@ void subghz_scene_decode_raw_on_enter(void* context) { subghz_receiver_set_rx_callback( subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); + subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_Decodable); if(subghz->decode_raw_state == SubGhzDecodeRawStateStart) { //Decode RAW to history diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 4fed9424c..778751dfe 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -117,7 +117,7 @@ void subghz_scene_read_raw_on_enter(void* context) { furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME)); //set filter RAW feed - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); + subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); } @@ -359,5 +359,5 @@ void subghz_scene_read_raw_on_exit(void* context) { notification_message(subghz->notifications, &sequence_reset_rgb); //filter restoration - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 752b26197..45b88b79b 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -256,8 +256,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, bin_raw_text[index]); - subghz->txrx->filter = bin_raw_value[index]; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + subghz->filter = bin_raw_value[index]; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); } static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { @@ -363,7 +363,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { BIN_RAW_COUNT, subghz_scene_receiver_config_set_bin_raw, subghz); - value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); + value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, bin_raw_text[value_index]); } diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index be3df0551..b2fca5a9e 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -305,8 +305,9 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz_environment_set_protocol_registry( subghz->txrx->environment, (void*)&subghz_protocol_registry); subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); - subghz->txrx->filter = SubGhzProtocolFlag_Decodable; - subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); + + subghz->filter = SubGhzProtocolFlag_Decodable; + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); subghz_worker_set_overrun_callback( subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 0914d12ed..a9594b789 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -94,6 +94,7 @@ struct SubGhz { #endif SubGhzLastSettings* last_settings; + SubGhzProtocolFlag filter; FuriString* error_str; SubGhzLock lock; diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index cd556efce..656306ed8 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -466,6 +466,11 @@ bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type) { txrx->decoder_result->protocol->encoder->deserialize); } +void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter) { + furi_assert(txrx); + subghz_receiver_set_filter(txrx->receiver, filter); +} + //#############Create new Key############## #include #include diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 0a51334cb..59f93733c 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -16,7 +16,6 @@ struct SubGhzTxRx { SubGhzEnvironment* environment; SubGhzReceiver* receiver; SubGhzTransmitter* transmitter; - SubGhzProtocolFlag filter; SubGhzProtocolDecoderBase* decoder_result; FlipperFormat* fff_data; @@ -87,6 +86,8 @@ SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx); bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* txrx); bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type); +void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter); + //#############Create new Key############## bool subghz_gen_data_protocol( void* context, From a2fbe7fab8e69598f460e6853bd0da8c51705859 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 17:30:01 +0300 Subject: [PATCH 163/216] SubGhz: refactoring --- .../scenes/subghz_scene_ext_module_settings.c | 4 +- applications/main/subghz/subghz.c | 98 +++++-------------- applications/main/subghz/subghz_radio.c | 70 +++++++++++++ applications/main/subghz/subghz_radio.h | 8 ++ 4 files changed, 102 insertions(+), 78 deletions(-) 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 508ca7dcc..963483db3 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -62,7 +62,7 @@ static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) { variable_item_set_current_value_text(item, debug_pin_text[index]); - subghz->txrx->debug_pin_state = index == 1; + subghz_txrx_set_debug_pin_state(subghz->txrx, index == 1); } static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) { @@ -164,7 +164,7 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { DEBUG_P_COUNT, subghz_scene_receiver_config_set_debug_pin, subghz); - value_index_dpin = subghz->txrx->debug_pin_state; + value_index_dpin = subghz_txrx_get_debug_pin_state(subghz->txrx); variable_item_set_current_value_index(item, value_index_dpin); variable_item_set_current_value_text(item, debug_pin_text[value_index_dpin]); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index b2fca5a9e..36a817117 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -180,11 +180,15 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz_test_static_get_view(subghz->subghz_test_static)); #endif - subghz->txrx = malloc(sizeof(SubGhzTxRx)); - //init setting - subghz->txrx->setting = subghz_setting_alloc(); + //init threshold rssi + subghz->threshold_rssi = subghz_threshold_rssi_alloc(); - subghz_setting_load(subghz->txrx->setting, EXT_PATH("subghz/assets/setting_user")); + //init TxRx & Protocol & History & KeyBoard + subghz_unlock(subghz); + + subghz->txrx = subghz_txrx_alloc(); + + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); // Custom Presets load without using config file if(!alloc_for_tx_only) { @@ -194,8 +198,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset); - subghz_setting_load_custom_preset( - subghz->txrx->setting, (const char*)"FM95", temp_fm_preset); + subghz_setting_load_custom_preset(setting, (const char*)"FM95", temp_fm_preset); flipper_format_free(temp_fm_preset); @@ -206,8 +209,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 03 47 08 32 0B 06 15 32 14 00 13 00 12 00 11 32 10 A7 18 18 19 1D 1D 92 1C 00 1B 04 20 FB 22 17 21 B6 00 00 00 12 0E 34 60 C5 C1 C0"); flipper_format_rewind(temp_fm_preset2); - subghz_setting_load_custom_preset( - subghz->txrx->setting, (const char*)"FM15k", temp_fm_preset2); + subghz_setting_load_custom_preset(setting, (const char*)"FM15k", temp_fm_preset2); flipper_format_free(temp_fm_preset2); @@ -218,8 +220,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset3); - subghz_setting_load_custom_preset( - subghz->txrx->setting, (const char*)"Pagers", temp_fm_preset3); + subghz_setting_load_custom_preset(setting, (const char*)"Pagers", temp_fm_preset3); flipper_format_free(temp_fm_preset3); @@ -230,8 +231,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset4); - subghz_setting_load_custom_preset( - subghz->txrx->setting, (const char*)"HND_1", temp_fm_preset4); + subghz_setting_load_custom_preset(setting, (const char*)"HND_1", temp_fm_preset4); flipper_format_free(temp_fm_preset4); @@ -241,8 +241,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { (const char*)"Custom_preset_data", (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset5); - subghz_setting_load_custom_preset( - subghz->txrx->setting, (const char*)"HND_2", temp_fm_preset5); + subghz_setting_load_custom_preset(setting, (const char*)"HND_2", temp_fm_preset5); flipper_format_free(temp_fm_preset5); } @@ -259,61 +258,24 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->last_settings->frequency, subghz->last_settings->preset); #endif - subghz_setting_set_default_frequency( - subghz->txrx->setting, subghz->last_settings->frequency); + subghz_setting_set_default_frequency(setting, subghz->last_settings->frequency); } - //init threshold rssi - subghz->threshold_rssi = subghz_threshold_rssi_alloc(); - - //init Worker & Protocol & History & KeyBoard - subghz_unlock(subghz); - - subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset)); - subghz->txrx->preset->name = furi_string_alloc(); if(!alloc_for_tx_only) { subghz_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); - } else { - subghz_set_preset( - subghz->txrx, - "AM650", - subghz_setting_get_default_frequency(subghz->txrx->setting), - NULL, - 0); } - subghz->txrx->txrx_state = SubGhzTxRxStateSleep; - subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); - subghz_speaker_set_state(subghz->txrx, SubGhzSpeakerStateDisable); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz->txrx->debug_pin_state = false; + if(!alloc_for_tx_only) { subghz->history = subghz_history_alloc(); } - subghz->txrx->worker = subghz_worker_alloc(); - - subghz->txrx->fff_data = flipper_format_string_alloc(); subghz->secure_data = malloc(sizeof(SecureData)); - subghz->txrx->environment = subghz_environment_alloc(); - subghz_environment_set_came_atomo_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry( - subghz->txrx->environment, (void*)&subghz_protocol_registry); - subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); - subghz->filter = SubGhzProtocolFlag_Decodable; - subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); - subghz_worker_set_overrun_callback( - subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); - subghz_worker_set_pair_callback( - subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); + subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); subghz_txrx_need_save_callback_set(subghz->txrx, subghz_save_to_file, subghz); @@ -405,8 +367,6 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - // setting - subghz_setting_free(subghz->txrx->setting); if(!alloc_for_tx_only) { subghz_last_settings_free(subghz->last_settings); } @@ -414,22 +374,14 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { // threshold rssi subghz_threshold_rssi_free(subghz->threshold_rssi); - //Worker & Protocol & History - - subghz_receiver_free(subghz->txrx->receiver); - - subghz_environment_free(subghz->txrx->environment); - - subghz_worker_free(subghz->txrx->worker); - - flipper_format_free(subghz->txrx->fff_data); if(!alloc_for_tx_only) { subghz_history_free(subghz->history); } - furi_string_free(subghz->txrx->preset->name); - free(subghz->txrx->preset); + free(subghz->secure_data); - free(subghz->txrx); + + //TxRx + subghz_txrx_free(subghz->txrx); //Error string furi_string_free(subghz->error_str); @@ -462,12 +414,6 @@ int32_t subghz_app(void* p) { subghz->raw_send_only = false; } - //Load database - bool load_database = subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); - // Call enable power for external module furi_hal_subghz_enable_ext_power(); @@ -512,7 +458,7 @@ int32_t subghz_app(void* p) { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); - if(load_database) { + if(subghz_txrx_is_load_database(subghz->txrx)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } else { scene_manager_set_scene_state( diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index 656306ed8..6e3ae3294 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -1,7 +1,77 @@ #include "subghz_radio.h" +#include #define TAG "SubGhz" +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* txrx = malloc(sizeof(SubGhzTxRx)); + txrx->setting = subghz_setting_alloc(); + subghz_setting_load(txrx->setting, EXT_PATH("subghz/assets/setting_user")); + + txrx->preset = malloc(sizeof(SubGhzRadioPreset)); + txrx->preset->name = furi_string_alloc(); + subghz_set_preset(txrx, "AM650", subghz_setting_get_default_frequency(txrx->setting), NULL, 0); + + txrx->txrx_state = SubGhzTxRxStateSleep; + + subghz_hopper_set_state(txrx, SubGhzHopperStateOFF); + subghz_speaker_set_state(txrx, SubGhzSpeakerStateDisable); + subghz_txrx_set_debug_pin_state(txrx, false); + + txrx->worker = subghz_worker_alloc(); + txrx->fff_data = flipper_format_string_alloc(); + + txrx->environment = subghz_environment_alloc(); + txrx->load_database = subghz_environment_load_keystore( + txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + txrx->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry(txrx->environment, (void*)&subghz_protocol_registry); + txrx->receiver = subghz_receiver_alloc_init(txrx->environment); + + subghz_worker_set_overrun_callback( + txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(txrx->worker, txrx->receiver); + + return txrx; +} + +void subghz_txrx_free(SubGhzTxRx* txrx) { + furi_assert(txrx); + + subghz_worker_free(txrx->worker); + subghz_receiver_free(txrx->receiver); + subghz_environment_free(txrx->environment); + flipper_format_free(txrx->fff_data); + furi_string_free(txrx->preset->name); + subghz_setting_free(txrx->setting); + free(txrx->preset); + free(txrx); +} + +bool subghz_txrx_is_load_database(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->load_database; +} + +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state) { + furi_assert(txrx); + txrx->debug_pin_state = state; +} + +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->debug_pin_state; +} + void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 59f93733c..5e5b1a82f 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -24,6 +24,7 @@ struct SubGhzTxRx { uint8_t hopper_timeout; uint8_t hopper_idx_frequency; + bool load_database; SubGhzHopperState hopper_state; SubGhzTxRxState txrx_state; @@ -38,6 +39,13 @@ struct SubGhzTxRx { typedef struct SubGhzTxRx SubGhzTxRx; +SubGhzTxRx* subghz_txrx_alloc(); +void subghz_txrx_free(SubGhzTxRx* txrx); +bool subghz_txrx_is_load_database(SubGhzTxRx* txrx); + +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state); +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx); + void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, From 8ae2cb1d32384baa98c76fb2ad8f006324aa74ed Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 18:24:25 +0300 Subject: [PATCH 164/216] SubGhz: refactoring --- .../subghz/scenes/subghz_scene_decode_raw.c | 9 ++-- .../subghz/scenes/subghz_scene_read_raw.c | 7 +-- .../subghz/scenes/subghz_scene_receiver.c | 13 +++--- .../subghz/scenes/subghz_scene_save_name.c | 12 ++--- .../subghz/scenes/subghz_scene_save_success.c | 2 +- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_radio.c | 46 +++++++++++++++++++ applications/main/subghz/subghz_radio.h | 36 ++++----------- 8 files changed, 75 insertions(+), 52 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index fa3082a3f..ef431a2c6 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -125,14 +125,14 @@ bool subghz_scene_decode_raw_start(SubGhz* subghz) { bool subghz_scene_decode_raw_next(SubGhz* subghz) { LevelDuration level_duration; - + SubGhzReceiver* receiver = subghz_txrx_get_receiver(subghz->txrx); for(uint32_t read = SAMPLES_TO_READ_PER_TICK; read > 0; --read) { level_duration = subghz_file_encoder_worker_get_level_duration(subghz->decode_raw_file_worker_encoder); if(!level_duration_is_reset(level_duration)) { bool level = level_duration_get_level(level_duration); uint32_t duration = level_duration_get_duration(level_duration); - subghz_receiver_decode(subghz->txrx->receiver, level, duration); + subghz_receiver_decode(receiver, level, duration); } else { subghz->decode_raw_state = SubGhzDecodeRawStateLoaded; subghz->state_notifications = SubGhzNotificationStateIDLE; @@ -167,8 +167,7 @@ void subghz_scene_decode_raw_on_enter(void* context) { subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz); - subghz_receiver_set_rx_callback( - subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz); subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_Decodable); @@ -214,7 +213,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { subghz->in_decoder_scene = false; subghz->in_decoder_scene_skip = false; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) { subghz_file_encoder_worker_stop(subghz->decode_raw_file_worker_encoder); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 778751dfe..5b20b04b1 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -228,11 +228,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { DOLPHIN_DEED(DolphinDeedSubGhzSend); } // set callback end tx - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - subghz->txrx->transmitter), - subghz_scene_read_raw_callback_end_tx, - subghz); + subghz_txrx_set_raw_file_encoder_worker_set_callback_end( + subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz); subghz->state_notifications = SubGhzNotificationStateTx; } } else { diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 72083fdeb..32e9cf6c8 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -153,32 +153,31 @@ void subghz_scene_receiver_on_enter(void* context) { subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); - subghz_receiver_set_rx_callback( - subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz); // TODO: Replace with proper solution based on protocol flags, remove kostily and velosipedy from here // Needs to be done after subghz refactoring merge!!! if(subghz->ignore_starline == true) { if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Star Line")) { subghz_protocol_decoder_base_set_decoder_callback( - subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, NULL); } } if(subghz->ignore_auto_alarms == true) { if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "KIA Seed")) { subghz_protocol_decoder_base_set_decoder_callback( - subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, NULL); } if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Scher-Khan")) { subghz_protocol_decoder_base_set_decoder_callback( - subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, NULL); } } if(subghz->ignore_magellan == true) { if(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, "Magellan")) { subghz_protocol_decoder_base_set_decoder_callback( - subghz_txrx_get_decoder(subghz->txrx), NULL, subghz->txrx->receiver); + subghz_txrx_get_decoder(subghz->txrx), NULL, NULL); } } @@ -205,7 +204,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); subghz->idx_menu_chosen = 0; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit); diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index ca48d6b45..c05230d97 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -57,15 +57,16 @@ void subghz_scene_save_name_on_enter(void* context) { if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; if(furi_hal_subghz_get_timestamp_file_names()) { - if(subghz->txrx->decoder_result != 0x0) { - if(subghz->txrx->decoder_result != NULL) { - if(strlen(subghz->txrx->decoder_result->protocol->name) != 0) { + SubGhzProtocolDecoderBase* decoder_result = subghz_txrx_get_decoder(subghz->txrx); + if(decoder_result != 0x0) { + if(decoder_result != NULL) { + if(strlen(decoder_result->protocol->name) != 0) { if(scene_manager_has_previous_scene( subghz->scene_manager, SubGhzSceneSetType)) { subghz_scene_save_name_get_timefilename(file_name, "S", true); } else { subghz_scene_save_name_get_timefilename( - file_name, subghz->txrx->decoder_result->protocol->name, false); + file_name, decoder_result->protocol->name, false); } } else { @@ -155,8 +156,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { } else { subghz_save_protocol_to_file( subghz, - subghz_history_get_raw_data( - subghz->history, subghz->idx_menu_chosen), + subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen), furi_string_get_cstr(subghz->file_path)); } } diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index ad37da086..0d0f9059e 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -40,7 +40,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) } else { subghz->decode_raw_state = SubGhzDecodeRawStateStart; subghz->idx_menu_chosen = 0; - subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); + subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) { subghz_file_encoder_worker_stop(subghz->decode_raw_file_worker_encoder); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 36a817117..f4fc1aa94 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -368,7 +368,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz->gui = NULL; if(!alloc_for_tx_only) { - subghz_last_settings_free(subghz->last_settings); + subghz_last_settings_free(subghz->last_settings); //TODO always allocated } // threshold rssi diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index 6e3ae3294..c5cb7d906 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -3,6 +3,33 @@ #define TAG "SubGhz" +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool load_database; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; + + bool debug_pin_state; +}; + SubGhzTxRx* subghz_txrx_alloc() { SubGhzTxRx* txrx = malloc(sizeof(SubGhzTxRx)); txrx->setting = subghz_setting_alloc(); @@ -541,6 +568,25 @@ void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter subghz_receiver_set_filter(txrx->receiver, filter); } +void subghz_txrx_set_rx_calback(SubGhzTxRx* txrx, SubGhzReceiverCallback callback, void* context) { + subghz_receiver_set_rx_callback(txrx->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( + SubGhzTxRx* txrx, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(txrx->transmitter), + callback, + context); +} + +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->receiver; +} + //#############Create new Key############## #include #include diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 5e5b1a82f..7745aa0ef 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -5,38 +5,12 @@ #include #include #include +#include #include "subghz_history.h" typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - - SubGhzRadioPreset* preset; - SubGhzSetting* setting; - - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - bool load_database; - SubGhzHopperState hopper_state; - - SubGhzTxRxState txrx_state; - - SubGhzSpeakerState speaker_state; - - SubGhzTxRxNeedSaveCallback need_save_callback; - void* need_save_context; - - bool debug_pin_state; -}; - typedef struct SubGhzTxRx SubGhzTxRx; SubGhzTxRx* subghz_txrx_alloc(); @@ -96,6 +70,14 @@ bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type); void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter); +void subghz_txrx_set_rx_calback(SubGhzTxRx* txrx, SubGhzReceiverCallback callback, void* context); +void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( + SubGhzTxRx* txrx, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context); + +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx); // TODO use only in DecodeRaw + //#############Create new Key############## bool subghz_gen_data_protocol( void* context, From 9b3654c1f0d4d8585e097759e8bf0a23ea0fb961 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 18:24:38 +0300 Subject: [PATCH 165/216] SubGhz: refactoring make subghz_radio.h look like in OFW --- applications/main/subghz/subghz_radio.c | 64 ++++++++++++------------- applications/main/subghz/subghz_radio.h | 7 ++- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/subghz_radio.c index c5cb7d906..556339bc3 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/subghz_radio.c @@ -89,16 +89,6 @@ bool subghz_txrx_is_load_database(SubGhzTxRx* txrx) { return txrx->load_database; } -void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state) { - furi_assert(txrx); - txrx->debug_pin_state = state; -} - -bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->debug_pin_state; -} - void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, @@ -112,28 +102,6 @@ void subghz_set_preset( txrx->preset->data_size = preset_data_size; } -void subghz_get_frequency_modulation( - SubGhzTxRx* txrx, - FuriString* frequency, - FuriString* modulation, - bool long_name) { - furi_assert(txrx); - if(frequency != NULL) { - furi_string_printf( - frequency, - "%03ld.%02ld", - txrx->preset->frequency / 1000000 % 1000, - txrx->preset->frequency / 10000 % 100); - } - if(modulation != NULL) { - if(long_name) { - furi_string_printf(modulation, "%s", furi_string_get_cstr(txrx->preset->name)); - } else { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(txrx->preset->name)); - } - } -} - const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset) { UNUSED(txrx); const char* preset_name = NULL; @@ -158,6 +126,28 @@ SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx) { return *txrx->preset; } +void subghz_get_frequency_modulation( + SubGhzTxRx* txrx, + FuriString* frequency, + FuriString* modulation, + bool long_name) { + furi_assert(txrx); + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + txrx->preset->frequency / 1000000 % 1000, + txrx->preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + if(long_name) { + furi_string_printf(modulation, "%s", furi_string_get_cstr(txrx->preset->name)); + } else { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(txrx->preset->name)); + } + } +} + static void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { furi_assert(txrx); furi_hal_subghz_reset(); @@ -582,6 +572,16 @@ void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( context); } +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state) { + furi_assert(txrx); + txrx->debug_pin_state = state; +} + +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx) { + furi_assert(txrx); + return txrx->debug_pin_state; +} + SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx) { furi_assert(txrx); return txrx->receiver; diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/subghz_radio.h index 7745aa0ef..dc6834ac1 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/subghz_radio.h @@ -17,9 +17,6 @@ SubGhzTxRx* subghz_txrx_alloc(); void subghz_txrx_free(SubGhzTxRx* txrx); bool subghz_txrx_is_load_database(SubGhzTxRx* txrx); -void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state); -bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx); - void subghz_set_preset( SubGhzTxRx* txrx, const char* preset_name, @@ -36,7 +33,6 @@ void subghz_get_frequency_modulation( FuriString* modulation, bool long_name); bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format); -//void subghz_rx_end(SubGhzTxRx* txrx); //depricated void subghz_rx_start(SubGhzTxRx* txrx); void subghz_txrx_stop(SubGhzTxRx* txrx); void subghz_sleep(SubGhzTxRx* txrx); @@ -76,6 +72,9 @@ void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( SubGhzProtocolEncoderRAWCallbackEnd callback, void* context); +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state); +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx); + SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx); // TODO use only in DecodeRaw //#############Create new Key############## From 4693af74e73515c8aeef526a434c55b9bf0312b3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 9 May 2023 18:44:17 +0300 Subject: [PATCH 166/216] Update API, remove direct calls of stream buffers --- firmware/targets/f7/api_symbols.csv | 50 +---------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 74c9b0f4f..96006c43c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -85,35 +85,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_adc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_bus.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_comp.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_cortex.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crs.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dma.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dmamux.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_exti.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_gpio.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_hsem.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_i2c.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_ipcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_iwdg.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lptim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lpuart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pka.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pwr.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rcc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rng.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rtc.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_spi.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_system.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_tim.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_usart.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, -Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, -Header,-,lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h,, -Header,+,lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -178,6 +149,7 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, @@ -205,7 +177,6 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, -Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/subghz/blocks/const.h,, Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, @@ -4505,7 +4476,6 @@ Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uE Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" -Function,-,ucStreamBufferGetStreamBufferType,uint8_t,StreamBufferHandle_t Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" @@ -4517,7 +4487,6 @@ Function,-,usbd_poll,void,usbd_device* Function,-,utf8_show,void, Function,-,utoa,char*,"unsigned, char*, int" Function,-,uxListRemove,UBaseType_t,ListItem_t* -Function,-,uxStreamBufferGetStreamBufferNumber,UBaseType_t,StreamBufferHandle_t Function,-,uxTaskGetNumberOfTasks,UBaseType_t, Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t @@ -4542,8 +4511,6 @@ Function,-,vPortFree,void,void* Function,-,vPortGetHeapStats,void,HeapStats_t* Function,-,vPortInitialiseBlocks,void, Function,-,vPortSuppressTicksAndSleep,void,TickType_t -Function,+,vStreamBufferDelete,void,StreamBufferHandle_t -Function,-,vStreamBufferSetStreamBufferNumber,void,"StreamBufferHandle_t, UBaseType_t" Function,-,vTaskAllocateMPURegions,void,"TaskHandle_t, const MemoryRegion_t*" Function,-,vTaskDelay,void,const TickType_t Function,-,vTaskDelete,void,TaskHandle_t @@ -4687,21 +4654,6 @@ Function,+,widget_reset,void,Widget* Function,-,xPortGetFreeHeapSize,size_t, Function,-,xPortGetMinimumEverFreeHeapSize,size_t, Function,-,xPortStartScheduler,BaseType_t, -Function,-,xStreamBufferBytesAvailable,size_t,StreamBufferHandle_t -Function,+,xStreamBufferGenericCreate,StreamBufferHandle_t,"size_t, size_t, BaseType_t" -Function,-,xStreamBufferGenericCreateStatic,StreamBufferHandle_t,"size_t, size_t, BaseType_t, uint8_t*, StaticStreamBuffer_t*" -Function,-,xStreamBufferIsEmpty,BaseType_t,StreamBufferHandle_t -Function,-,xStreamBufferIsFull,BaseType_t,StreamBufferHandle_t -Function,-,xStreamBufferNextMessageLengthBytes,size_t,StreamBufferHandle_t -Function,+,xStreamBufferReceive,size_t,"StreamBufferHandle_t, void*, size_t, TickType_t" -Function,-,xStreamBufferReceiveCompletedFromISR,BaseType_t,"StreamBufferHandle_t, BaseType_t*" -Function,-,xStreamBufferReceiveFromISR,size_t,"StreamBufferHandle_t, void*, size_t, BaseType_t*" -Function,-,xStreamBufferReset,BaseType_t,StreamBufferHandle_t -Function,-,xStreamBufferSend,size_t,"StreamBufferHandle_t, const void*, size_t, TickType_t" -Function,-,xStreamBufferSendCompletedFromISR,BaseType_t,"StreamBufferHandle_t, BaseType_t*" -Function,+,xStreamBufferSendFromISR,size_t,"StreamBufferHandle_t, const void*, size_t, BaseType_t*" -Function,-,xStreamBufferSetTriggerLevel,BaseType_t,"StreamBufferHandle_t, size_t" -Function,-,xStreamBufferSpacesAvailable,size_t,StreamBufferHandle_t Function,-,xTaskAbortDelay,BaseType_t,TaskHandle_t Function,-,xTaskCallApplicationTaskHook,BaseType_t,"TaskHandle_t, void*" Function,-,xTaskCatchUpTicks,BaseType_t,TickType_t From d7f3b8a4254777da7e4506424f8f89abef236871 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 19:10:56 +0300 Subject: [PATCH 167/216] SubGhz: refactoring move txrx --- .../{subghz_radio.c => helpers/subghz_txrx.c} | 554 +++++++++--------- .../{subghz_radio.h => helpers/subghz_txrx.h} | 95 +-- .../subghz/scenes/subghz_scene_decode_raw.c | 4 +- .../main/subghz/scenes/subghz_scene_delete.c | 2 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_need_saving.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 14 +- .../subghz/scenes/subghz_scene_receiver.c | 21 +- .../scenes/subghz_scene_receiver_config.c | 26 +- .../scenes/subghz_scene_receiver_info.c | 22 +- .../main/subghz/scenes/subghz_scene_rpc.c | 2 +- .../subghz/scenes/subghz_scene_set_type.c | 38 +- .../subghz/scenes/subghz_scene_transmitter.c | 6 +- applications/main/subghz/subghz.c | 18 +- applications/main/subghz/subghz_i.c | 4 +- applications/main/subghz/subghz_i.h | 6 +- 16 files changed, 416 insertions(+), 400 deletions(-) rename applications/main/subghz/{subghz_radio.c => helpers/subghz_txrx.c} (53%) rename applications/main/subghz/{subghz_radio.h => helpers/subghz_txrx.h} (50%) diff --git a/applications/main/subghz/subghz_radio.c b/applications/main/subghz/helpers/subghz_txrx.c similarity index 53% rename from applications/main/subghz/subghz_radio.c rename to applications/main/subghz/helpers/subghz_txrx.c index 556339bc3..c99b95e09 100644 --- a/applications/main/subghz/subghz_radio.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,4 +1,4 @@ -#include "subghz_radio.h" +#include "subghz_txrx.h" #include #define TAG "SubGhz" @@ -21,7 +21,6 @@ struct SubGhzTxRx { SubGhzHopperState hopper_state; SubGhzTxRxState txrx_state; - SubGhzSpeakerState speaker_state; SubGhzTxRxNeedSaveCallback need_save_callback; @@ -31,79 +30,81 @@ struct SubGhzTxRx { }; SubGhzTxRx* subghz_txrx_alloc() { - SubGhzTxRx* txrx = malloc(sizeof(SubGhzTxRx)); - txrx->setting = subghz_setting_alloc(); - subghz_setting_load(txrx->setting, EXT_PATH("subghz/assets/setting_user")); + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); - txrx->preset = malloc(sizeof(SubGhzRadioPreset)); - txrx->preset->name = furi_string_alloc(); - subghz_set_preset(txrx, "AM650", subghz_setting_get_default_frequency(txrx->setting), NULL, 0); + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); - txrx->txrx_state = SubGhzTxRxStateSleep; + instance->txrx_state = SubGhzTxRxStateSleep; - subghz_hopper_set_state(txrx, SubGhzHopperStateOFF); - subghz_speaker_set_state(txrx, SubGhzSpeakerStateDisable); - subghz_txrx_set_debug_pin_state(txrx, false); + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + subghz_txrx_set_debug_pin_state(instance, false); - txrx->worker = subghz_worker_alloc(); - txrx->fff_data = flipper_format_string_alloc(); + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); - txrx->environment = subghz_environment_alloc(); - txrx->load_database = subghz_environment_load_keystore( - txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + instance->environment = subghz_environment_alloc(); + instance->load_database = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); subghz_environment_load_keystore( - txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); subghz_environment_set_came_atomo_rainbow_table_file_name( - txrx->environment, EXT_PATH("subghz/assets/came_atomo")); + instance->environment, EXT_PATH("subghz/assets/came_atomo")); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry(txrx->environment, (void*)&subghz_protocol_registry); - txrx->receiver = subghz_receiver_alloc_init(txrx->environment); + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); subghz_worker_set_overrun_callback( - txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); subghz_worker_set_pair_callback( - txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); - subghz_worker_set_context(txrx->worker, txrx->receiver); + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); - return txrx; + return instance; } -void subghz_txrx_free(SubGhzTxRx* txrx) { - furi_assert(txrx); +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); - subghz_worker_free(txrx->worker); - subghz_receiver_free(txrx->receiver); - subghz_environment_free(txrx->environment); - flipper_format_free(txrx->fff_data); - furi_string_free(txrx->preset->name); - subghz_setting_free(txrx->setting); - free(txrx->preset); - free(txrx); + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); } -bool subghz_txrx_is_load_database(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->load_database; +bool subghz_txrx_is_load_database(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->load_database; } -void subghz_set_preset( - SubGhzTxRx* txrx, +void subghz_txrx_set_preset( + SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, uint8_t* preset_data, size_t preset_data_size) { - furi_assert(txrx); - furi_string_set(txrx->preset->name, preset_name); - txrx->preset->frequency = frequency; - txrx->preset->data = preset_data; - txrx->preset->data_size = preset_data_size; + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + instance->preset->frequency = frequency; + instance->preset->data = preset_data; + instance->preset->data_size = preset_data_size; } -const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset) { - UNUSED(txrx); +const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); const char* preset_name = NULL; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { preset_name = "AM270"; @@ -121,95 +122,96 @@ const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset) { return preset_name; } -SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx) { - furi_assert(txrx); - return *txrx->preset; +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; } -void subghz_get_frequency_modulation( - SubGhzTxRx* txrx, +void subghz_txrx_get_frequency_modulation( + SubGhzTxRx* instance, FuriString* frequency, FuriString* modulation, bool long_name) { - furi_assert(txrx); + furi_assert(instance); if(frequency != NULL) { furi_string_printf( frequency, "%03ld.%02ld", - txrx->preset->frequency / 1000000 % 1000, - txrx->preset->frequency / 10000 % 100); + instance->preset->frequency / 1000000 % 1000, + instance->preset->frequency / 10000 % 100); } if(modulation != NULL) { if(long_name) { - furi_string_printf(modulation, "%s", furi_string_get_cstr(txrx->preset->name)); + furi_string_printf(modulation, "%s", furi_string_get_cstr(instance->preset->name)); } else { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(txrx->preset->name)); + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(instance->preset->name)); } } } -static void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) { - furi_assert(txrx); +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_custom_preset(preset_data); furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - txrx->txrx_state = SubGhzTxRxStateIDLE; + instance->txrx_state = SubGhzTxRxStateIDLE; } -static uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency) { - furi_assert(txrx); +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); if(!furi_hal_subghz_is_frequency_valid(frequency)) { furi_crash("SubGhz: Incorrect RX frequency."); } - furi_assert(txrx->txrx_state != SubGhzTxRxStateRx && txrx->txrx_state != SubGhzTxRxStateSleep); + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); - subghz_speaker_on(txrx); + subghz_txrx_speaker_on(instance); furi_hal_subghz_rx(); - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, txrx->worker); - subghz_worker_start(txrx->worker); - txrx->txrx_state = SubGhzTxRxStateRx; + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; return value; } -static void subghz_idle(SubGhzTxRx* txrx) { - furi_assert(txrx); - furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep); +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); - subghz_speaker_off(txrx); - txrx->txrx_state = SubGhzTxRxStateIDLE; + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; } -static void subghz_rx_end(SubGhzTxRx* txrx) { - furi_assert(txrx); - furi_assert(txrx->txrx_state == SubGhzTxRxStateRx); +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); - if(subghz_worker_is_running(txrx->worker)) { - subghz_worker_stop(txrx->worker); + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); furi_hal_subghz_stop_async_rx(); } furi_hal_subghz_idle(); - subghz_speaker_off(txrx); - txrx->txrx_state = SubGhzTxRxStateIDLE; + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; } -void subghz_sleep(SubGhzTxRx* txrx) { - furi_assert(txrx); +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); furi_hal_subghz_sleep(); - txrx->txrx_state = SubGhzTxRxStateSleep; + instance->txrx_state = SubGhzTxRxStateSleep; } -static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) { - furi_assert(txrx); +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); if(!furi_hal_subghz_is_frequency_valid(frequency)) { furi_crash("SubGhz: Incorrect TX frequency."); } - furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); @@ -217,17 +219,17 @@ static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) { furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); bool ret = furi_hal_subghz_tx(); if(ret) { - subghz_speaker_on(txrx); - txrx->txrx_state = SubGhzTxRxStateTx; + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; } return ret; } -bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { - furi_assert(txrx); +bool subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); furi_assert(flipper_format); - subghz_txrx_stop(txrx); + subghz_txrx_stop(instance); bool ret = false; FuriString* temp_str = furi_string_alloc(); @@ -246,33 +248,35 @@ bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { break; } - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, furi_string_get_cstr(temp_str)); + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); - if(txrx->transmitter) { - if(subghz_transmitter_deserialize(txrx->transmitter, flipper_format) == + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(txrx->preset->name), "") != 0) { - subghz_begin( - txrx, + if(strcmp(furi_string_get_cstr(instance->preset->name), "") != 0) { + subghz_txrx_begin( + instance, subghz_setting_get_preset_data_by_name( - txrx->setting, furi_string_get_cstr(txrx->preset->name))); + instance->setting, furi_string_get_cstr(instance->preset->name))); } else { FURI_LOG_E( TAG, "Unknown name preset \" %s \"", - furi_string_get_cstr(txrx->preset->name)); - subghz_begin( - txrx, subghz_setting_get_preset_data_by_name(txrx->setting, "AM650")); + furi_string_get_cstr(instance->preset->name)); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name(instance->setting, "AM650")); } - if(txrx->preset->frequency) { - ret = subghz_tx(txrx, txrx->preset->frequency); + if(instance->preset->frequency) { + ret = subghz_txrx_tx(instance, instance->preset->frequency); } else { - ret = subghz_tx(txrx, 433920000); + ret = subghz_txrx_tx(instance, 433920000); } if(ret) { //Start TX - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, txrx->transmitter); + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); } else { //Todo: Show error //subghz_dialog_message_show_only_rx(subghz); @@ -284,9 +288,9 @@ bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { } } if(!ret) { - subghz_transmitter_free(txrx->transmitter); - if(txrx->txrx_state != SubGhzTxRxStateSleep) { - subghz_idle(txrx); + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); } } @@ -295,68 +299,68 @@ bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) { return ret; } -void subghz_rx_start(SubGhzTxRx* txrx) { - furi_assert(txrx); - subghz_txrx_stop(txrx); - subghz_begin( - txrx, +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, subghz_setting_get_preset_data_by_name( - subghz_txrx_get_setting(txrx), furi_string_get_cstr(txrx->preset->name))); - subghz_rx(txrx, txrx->preset->frequency); + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); } void subghz_txrx_need_save_callback_set( - SubGhzTxRx* txrx, + SubGhzTxRx* instance, SubGhzTxRxNeedSaveCallback callback, void* context) { - furi_assert(txrx); - txrx->need_save_callback = callback; - txrx->need_save_context = context; + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; } -static void subghz_tx_stop(SubGhzTxRx* txrx) { - furi_assert(txrx); - furi_assert(txrx->txrx_state == SubGhzTxRxStateTx); +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); //Stop TX furi_hal_subghz_stop_async_tx(); - subghz_transmitter_stop(txrx->transmitter); - subghz_transmitter_free(txrx->transmitter); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); //if protocol dynamic then we save the last upload - if(txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { - if(txrx->need_save_callback) { - txrx->need_save_callback(txrx->need_save_context); + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); } } - subghz_idle(txrx); - subghz_speaker_off(txrx); + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); //Todo: Show message // notification_message(notifications, &sequence_reset_red); } -FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->fff_data; +FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; } -SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->setting; +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; } -void subghz_txrx_stop(SubGhzTxRx* txrx) { - furi_assert(txrx); +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); - switch(txrx->txrx_state) { + switch(instance->txrx_state) { case SubGhzTxRxStateTx: - subghz_tx_stop(txrx); - subghz_speaker_unmute(txrx); - //subghz_sleep(txrx); + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + //subghz_txrx_sleep(txrx); break; case SubGhzTxRxStateRx: - subghz_rx_end(txrx); - subghz_speaker_mute(txrx); - //subghz_sleep(txrx); + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + //subghz_txrx_sleep(txrx); break; default: @@ -364,21 +368,21 @@ void subghz_txrx_stop(SubGhzTxRx* txrx) { } } -SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->txrx_state; +SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->txrx_state; } -void subghz_hopper_update(SubGhzTxRx* txrx) { - furi_assert(txrx); +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); - switch(txrx->hopper_state) { + switch(instance->hopper_state) { case SubGhzHopperStateOFF: case SubGhzHopperStatePause: return; case SubGhzHopperStateRSSITimeOut: - if(txrx->hopper_timeout != 0) { - txrx->hopper_timeout--; + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; return; } break; @@ -386,205 +390,209 @@ void subghz_hopper_update(SubGhzTxRx* txrx) { break; } float rssi = -127.0f; - if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { // See RSSI Calculation timings in CC1101 17.3 RSSI rssi = furi_hal_subghz_get_rssi(); // Stay if RSSI is high enough if(rssi > -90.0f) { - txrx->hopper_timeout = 10; - txrx->hopper_state = SubGhzHopperStateRSSITimeOut; + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; return; } } else { - txrx->hopper_state = SubGhzHopperStateRunning; + instance->hopper_state = SubGhzHopperStateRunning; } // Select next frequency - if(txrx->hopper_idx_frequency < subghz_setting_get_hopper_frequency_count(txrx->setting) - 1) { - txrx->hopper_idx_frequency++; + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; } else { - txrx->hopper_idx_frequency = 0; + instance->hopper_idx_frequency = 0; } - if(txrx->txrx_state == SubGhzTxRxStateRx) { - subghz_rx_end(txrx); + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); }; - if(txrx->txrx_state == SubGhzTxRxStateIDLE) { - subghz_receiver_reset(txrx->receiver); - txrx->preset->frequency = - subghz_setting_get_hopper_frequency(txrx->setting, txrx->hopper_idx_frequency); - subghz_rx(txrx, txrx->preset->frequency); + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); } } -SubGhzHopperState subghz_hopper_get_state(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->hopper_state; +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; } -void subghz_hopper_set_state(SubGhzTxRx* txrx, SubGhzHopperState state) { - furi_assert(txrx); - txrx->hopper_state = state; +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; } -void subghz_hopper_remove_pause(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->hopper_state == SubGhzHopperStatePause) { - txrx->hopper_state = SubGhzHopperStateRunning; +void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunning; } } -void subghz_subghz_hopper_set_pause(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->hopper_state == SubGhzHopperStateRunning) { - txrx->hopper_state = SubGhzHopperStatePause; +void subghz_txrx_hopper_set_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunning) { + instance->hopper_state = SubGhzHopperStatePause; } } -void subghz_speaker_on(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->debug_pin_state) { +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); } - if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_acquire(30)) { - if(!txrx->debug_pin_state) { + if(!instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); } } else { - txrx->speaker_state = SubGhzSpeakerStateDisable; + instance->speaker_state = SubGhzSpeakerStateDisable; } } } -void subghz_speaker_off(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->debug_pin_state) { +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(NULL); } - if(txrx->speaker_state != SubGhzSpeakerStateDisable) { + if(instance->speaker_state != SubGhzSpeakerStateDisable) { if(furi_hal_speaker_is_mine()) { - if(!txrx->debug_pin_state) { + if(!instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(NULL); } furi_hal_speaker_release(); - if(txrx->speaker_state == SubGhzSpeakerStateShutdown) - txrx->speaker_state = SubGhzSpeakerStateDisable; + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; } } } -void subghz_speaker_mute(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->debug_pin_state) { +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(NULL); } - if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - if(!txrx->debug_pin_state) { + if(!instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(NULL); } } } } -void subghz_speaker_unmute(SubGhzTxRx* txrx) { - furi_assert(txrx); - if(txrx->debug_pin_state) { +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); } - if(txrx->speaker_state == SubGhzSpeakerStateEnable) { + if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - if(!txrx->debug_pin_state) { + if(!instance->debug_pin_state) { furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); } } } } -void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state) { - furi_assert(txrx); - txrx->speaker_state = state; +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; } -SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->speaker_state; +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; } -bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* txrx, const char* name_protocol) { - furi_assert(txrx); +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); furi_assert(name_protocol); bool res = false; - txrx->decoder_result = NULL; - txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(txrx->receiver, name_protocol); - if(txrx->decoder_result) { + instance->decoder_result = NULL; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { res = true; } return res; } -SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->decoder_result; +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; } -bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* txrx) { - furi_assert(txrx); +bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance) { + furi_assert(instance); return ( - (txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == SubGhzProtocolFlag_Save); } -bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type) { - furi_assert(txrx); +bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); if(check_type) { return ( - ((txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == + ((instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && - txrx->decoder_result->protocol->encoder->deserialize && - txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic); + instance->decoder_result->protocol->encoder->deserialize && + instance->decoder_result->protocol->type == SubGhzProtocolTypeStatic); } return ( - ((txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == + ((instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && - txrx->decoder_result->protocol->encoder->deserialize); + instance->decoder_result->protocol->encoder->deserialize); } -void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter) { - furi_assert(txrx); - subghz_receiver_set_filter(txrx->receiver, filter); +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); } -void subghz_txrx_set_rx_calback(SubGhzTxRx* txrx, SubGhzReceiverCallback callback, void* context) { - subghz_receiver_set_rx_callback(txrx->receiver, callback, context); +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); } void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( - SubGhzTxRx* txrx, + SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context) { subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(txrx->transmitter), + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), callback, context); } -void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state) { - furi_assert(txrx); - txrx->debug_pin_state = state; +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state) { + furi_assert(instance); + instance->debug_pin_state = state; } -bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->debug_pin_state; +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->debug_pin_state; } -SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx) { - furi_assert(txrx); - return txrx->receiver; +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->receiver; } //#############Create new Key############## @@ -598,7 +606,7 @@ SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx) { #include #include -bool subghz_gen_data_protocol( +bool subghz_txrx_gen_data_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -606,15 +614,15 @@ bool subghz_gen_data_protocol( uint64_t key, uint32_t bit) { furi_assert(context); - SubGhzTxRx* txrx = context; + SubGhzTxRx* instance = context; bool res = false; - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); - txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(txrx->receiver, protocol_name); + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); - if(txrx->decoder_result == NULL) { + if(instance->decoder_result == NULL) { //TODO: Error // furi_string_set(error_str, "Protocol not\nfound!"); // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); @@ -622,14 +630,15 @@ bool subghz_gen_data_protocol( } do { - Stream* fff_data_stream = flipper_format_get_raw_stream(txrx->fff_data); + Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); stream_clean(fff_data_stream); if(subghz_protocol_decoder_base_serialize( - txrx->decoder_result, txrx->fff_data, txrx->preset) != SubGhzProtocolStatusOk) { + instance->decoder_result, instance->fff_data, instance->preset) != + SubGhzProtocolStatusOk) { FURI_LOG_E(TAG, "Unable to serialize"); break; } - if(!flipper_format_update_uint32(txrx->fff_data, "Bit", &bit, 1)) { + if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { FURI_LOG_E(TAG, "Unable to update Bit"); break; } @@ -638,7 +647,7 @@ bool subghz_gen_data_protocol( for(size_t i = 0; i < sizeof(uint64_t); i++) { key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; } - if(!flipper_format_update_hex(txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { + if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { FURI_LOG_E(TAG, "Unable to update Key"); break; } @@ -647,18 +656,18 @@ bool subghz_gen_data_protocol( return res; } -bool subghz_gen_data_protocol_and_te( - SubGhzTxRx* txrx, +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, const char* protocol_name, uint64_t key, uint32_t bit, uint32_t te) { - furi_assert(txrx); + furi_assert(instance); bool ret = false; - if(subghz_gen_data_protocol(txrx, preset_name, frequency, protocol_name, key, bit)) { - if(!flipper_format_update_uint32(txrx->fff_data, "TE", (uint32_t*)&te, 1)) { + if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { FURI_LOG_E(TAG, "Unable to update Te"); } else { ret = true; @@ -681,7 +690,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_keeloq_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -713,7 +722,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -757,7 +766,7 @@ bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -790,7 +799,7 @@ bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_faac_slh_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -831,7 +840,7 @@ bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -861,7 +870,7 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); - subghz_set_preset(txrx, preset_name, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); if(txrx->transmitter && subghz_protocol_somfy_telis_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -878,7 +887,7 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename return res; } -bool subghz_gen_secplus_v2_protocol( +bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency, @@ -890,7 +899,7 @@ bool subghz_gen_secplus_v2_protocol( bool ret = false; txrx->transmitter = subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_set_preset(txrx, name_preset, frequency, NULL, 0); + subghz_txrx_set_preset(txrx, name_preset, frequency, NULL, 0); if(txrx->transmitter) { subghz_protocol_secplus_v2_create_data( subghz_transmitter_get_protocol_instance(txrx->transmitter), @@ -904,7 +913,10 @@ bool subghz_gen_secplus_v2_protocol( return ret; } -bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency) { +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* txrx, + const char* name_preset, + uint32_t frequency) { furi_assert(txrx); bool ret = false; @@ -912,7 +924,7 @@ bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, u while(!subghz_protocol_secplus_v1_check_fixed(serial)) { serial = (uint32_t)rand(); } - if(subghz_gen_data_protocol( + if(subghz_txrx_gen_data_protocol( txrx, name_preset, frequency, diff --git a/applications/main/subghz/subghz_radio.h b/applications/main/subghz/helpers/subghz_txrx.h similarity index 50% rename from applications/main/subghz/subghz_radio.h rename to applications/main/subghz/helpers/subghz_txrx.h index dc6834ac1..cb50e8334 100644 --- a/applications/main/subghz/subghz_radio.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -1,84 +1,84 @@ #pragma once -//#include "subghz_i.h" -#include "helpers/subghz_types.h" +#include "subghz_types.h" #include #include #include #include #include -#include "subghz_history.h" - typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); typedef struct SubGhzTxRx SubGhzTxRx; SubGhzTxRx* subghz_txrx_alloc(); -void subghz_txrx_free(SubGhzTxRx* txrx); -bool subghz_txrx_is_load_database(SubGhzTxRx* txrx); +void subghz_txrx_free(SubGhzTxRx* instance); +bool subghz_txrx_is_load_database(SubGhzTxRx* instance); -void subghz_set_preset( - SubGhzTxRx* txrx, +void subghz_txrx_set_preset( + SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, uint8_t* preset_data, size_t preset_data_size); -const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset); -SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx); +const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset); +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); -void subghz_get_frequency_modulation( - SubGhzTxRx* txrx, +void subghz_txrx_get_frequency_modulation( + SubGhzTxRx* instance, FuriString* frequency, FuriString* modulation, bool long_name); -bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format); -void subghz_rx_start(SubGhzTxRx* txrx); -void subghz_txrx_stop(SubGhzTxRx* txrx); -void subghz_sleep(SubGhzTxRx* txrx); +bool subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); +void subghz_txrx_rx_start(SubGhzTxRx* instance); +void subghz_txrx_stop(SubGhzTxRx* instance); +void subghz_txrx_sleep(SubGhzTxRx* instance); -SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx); +SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* instance); -void subghz_hopper_update(SubGhzTxRx* txrx); -SubGhzHopperState subghz_hopper_get_state(SubGhzTxRx* txrx); -void subghz_hopper_set_state(SubGhzTxRx* txrx, SubGhzHopperState state); -void subghz_hopper_remove_pause(SubGhzTxRx* txrx); -void subghz_subghz_hopper_set_pause(SubGhzTxRx* txrx); +void subghz_txrx_hopper_update(SubGhzTxRx* instance); +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); +void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance); +void subghz_txrx_hopper_set_pause(SubGhzTxRx* instance); -void subghz_speaker_on(SubGhzTxRx* txrx); -void subghz_speaker_off(SubGhzTxRx* txrx); -void subghz_speaker_mute(SubGhzTxRx* txrx); -void subghz_speaker_unmute(SubGhzTxRx* txrx); -void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state); -SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx); -bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* txrx, const char* name_protocol); -SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx); +void subghz_txrx_speaker_on(SubGhzTxRx* instance); +void subghz_txrx_speaker_off(SubGhzTxRx* instance); +void subghz_txrx_speaker_mute(SubGhzTxRx* instance); +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); void subghz_txrx_need_save_callback_set( - SubGhzTxRx* txrx, + SubGhzTxRx* instance, SubGhzTxRxNeedSaveCallback callback, void* context); -FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx); -SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx); +FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance); +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); -bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* txrx); -bool subghz_txrx_protocol_is_send(SubGhzTxRx* txrx, bool check_type); +bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance); +bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type); -void subghz_txrx_receiver_set_filter(SubGhzTxRx* txrx, SubGhzProtocolFlag filter); +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); -void subghz_txrx_set_rx_calback(SubGhzTxRx* txrx, SubGhzReceiverCallback callback, void* context); +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context); void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( - SubGhzTxRx* txrx, + SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context); -void subghz_txrx_set_debug_pin_state(SubGhzTxRx* txrx, bool state); -bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* txrx); +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state); +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance); -SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* txrx); // TODO use only in DecodeRaw +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw //#############Create new Key############## -bool subghz_gen_data_protocol( +bool subghz_txrx_gen_data_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -86,8 +86,8 @@ bool subghz_gen_data_protocol( uint64_t key, uint32_t bit); -bool subghz_gen_data_protocol_and_te( - SubGhzTxRx* txrx, +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, const char* protocol_name, @@ -149,7 +149,7 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename uint8_t btn, uint16_t cnt); -bool subghz_gen_secplus_v2_protocol( +bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency, @@ -157,4 +157,7 @@ bool subghz_gen_secplus_v2_protocol( uint8_t btn, uint32_t cnt); -bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency); \ No newline at end of file +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* txrx, + const char* name_preset, + uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index ef431a2c6..f008db380 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -29,7 +29,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, @@ -61,7 +61,7 @@ static void subghz_scene_add_to_history_callback( FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->history); - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); if(subghz_history_add_to_history(subghz->history, decoder_base, &preset)) { furi_string_reset(item_name); diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index cf0bdefb1..095cdf899 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -15,7 +15,7 @@ void subghz_scene_delete_on_enter(void* context) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index ed960d666..bc8a4d6ef 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -30,7 +30,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index b0fc70b8b..c249ff282 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -48,7 +48,7 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneExit) { if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateExit) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 5b20b04b1..298ffda06 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -41,8 +41,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, true); - //TODO if need subghz_get_preset + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, true); + //TODO if need subghz_txrx_get_preset //furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); #else subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); @@ -140,7 +140,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { //Restore default setting if(subghz->raw_send_only) { - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, "AM650", subghz_setting_get_default_frequency( @@ -148,7 +148,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { NULL, 0); } else { - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } if(!scene_manager_search_and_switch_to_previous_scene( @@ -215,7 +215,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); - if(!subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( subghz->subghz_read_raw, @@ -280,13 +280,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); if(subghz_protocol_raw_save_to_file_init( (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); - subghz_rx_start(subghz->txrx); + subghz_txrx_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 32e9cf6c8..7570d822d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -46,11 +46,12 @@ static void subghz_scene_receiver_update_statusbar(void* context) { #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->history) > 0) { - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation( + subghz->txrx, frequency_str, modulation_str, false); } else { FuriString* temp_str = furi_string_alloc(); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, temp_str, true); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, temp_str, true); furi_string_printf( modulation_str, "%s Mod: %s", @@ -59,7 +60,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { furi_string_free(temp_str); } #else - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); #endif subghz_view_receiver_add_data_statusbar( @@ -96,7 +97,7 @@ static void subghz_scene_add_to_history_callback( FuriString* item_time = furi_string_alloc(); uint16_t idx = subghz_history_get_item(subghz->history); - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); if(subghz_history_add_to_history(subghz->history, decoder_base, &preset)) { furi_string_reset(item_name); furi_string_reset(item_time); @@ -126,7 +127,7 @@ void subghz_scene_receiver_on_enter(void* context) { FuriString* item_time = furi_string_alloc(); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { - subghz_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_txrx_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); subghz_history_reset(subghz->history); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } @@ -183,7 +184,7 @@ void subghz_scene_receiver_on_enter(void* context) { subghz->state_notifications = SubGhzNotificationStateRx; subghz_txrx_stop(subghz->txrx); - subghz_rx_start(subghz->txrx); + subghz_txrx_rx_start(subghz->txrx); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); //to use a universal decoder, we are looking for a link to it @@ -202,7 +203,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); - subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); subghz->idx_menu_chosen = 0; subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz); @@ -211,7 +212,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); @@ -254,8 +255,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { break; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz->txrx); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); subghz_scene_receiver_update_statusbar(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 45b88b79b..d65778b01 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -149,7 +149,7 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - if(subghz_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { + if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; snprintf( text_buf, @@ -161,16 +161,16 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { 10000); variable_item_set_current_value_text(item, text_buf); - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index), preset.data, preset.data_size); - preset = subghz_get_preset(subghz->txrx); + preset = subghz_txrx_get_preset(subghz->txrx); subghz->last_settings->frequency = preset.frequency; subghz_setting_set_default_frequency( @@ -189,9 +189,9 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), index); variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, preset_name, preset.frequency, @@ -218,8 +218,8 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), text_buf); - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); - subghz_set_preset( + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), @@ -240,7 +240,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); } - subghz_hopper_set_state(subghz->txrx, hopping_value[index]); + subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]); } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -248,7 +248,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); - subghz_speaker_set_state(subghz->txrx, speaker_value[index]); + subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]); } static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { @@ -305,7 +305,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; - SubGhzRadioPreset preset = subghz_get_preset(subghz->txrx); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, @@ -350,7 +350,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( - subghz_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); + subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); } @@ -412,7 +412,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_speaker, subghz); value_index = - value_index_uint32(subghz_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); + value_index_uint32(subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index f3cfd0962..019898025 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -34,7 +34,7 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { SubGhzRadioPreset* preset = subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset->name), preset->frequency, @@ -52,7 +52,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, @@ -118,17 +118,17 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { //CC1101 Stop RX -> Start TX - subghz_subghz_hopper_set_pause(subghz->txrx); + subghz_txrx_hopper_set_pause(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(!subghz_tx_start( + if(!subghz_txrx_tx_start( subghz->txrx, subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { - subghz_rx_start(subghz->txrx); - subghz_hopper_remove_pause(subghz->txrx); + subghz_txrx_rx_start(subghz->txrx); + subghz_txrx_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } else { subghz->state_notifications = SubGhzNotificationStateTx; @@ -143,16 +143,16 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_txrx_stop(subghz->txrx); if(!subghz->in_decoder_scene) { - subghz_rx_start(subghz->txrx); + subghz_txrx_rx_start(subghz->txrx); - subghz_hopper_remove_pause(subghz->txrx); + subghz_txrx_hopper_remove_pause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } return true; } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = SubGhzNotificationStateIDLE; - subghz_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); + subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF); subghz_txrx_stop(subghz->txrx); if(!subghz_scene_receiver_info_update_parser(subghz)) { @@ -170,8 +170,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return true; } } else if(event.type == SceneManagerEventTypeTick) { - if(subghz_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { - subghz_hopper_update(subghz->txrx); + if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) { + subghz_txrx_hopper_update(subghz->txrx); } switch(subghz->state_notifications) { case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 2af4112cf..680eae7bc 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -44,7 +44,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { bool result = false; if((subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateSleep) && (state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx)); + result = subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx)); if(result) subghz_blink_start(subghz); } if(!result) { diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 4bbf1c769..87ef6b0af 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -305,64 +305,64 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { break; case SubmenuIndexPricenton433: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - generated_protocol = subghz_gen_data_protocol_and_te( + generated_protocol = subghz_txrx_gen_data_protocol_and_te( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexPricenton315: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - generated_protocol = subghz_gen_data_protocol_and_te( + generated_protocol = subghz_txrx_gen_data_protocol_and_te( subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400); break; case SubmenuIndexNiceFlo12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12); break; case SubmenuIndexNiceFlo24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24); break; case SubmenuIndexCAME12bit: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexCAME12bit868: key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12); break; case SubmenuIndexCAME24bit868: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 868350000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24); break; case SubmenuIndexLinear_300_00: key = (key & 0x3FF); - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10); break; case SubmenuIndexBETT_433: key = (key & 0x0000FFF0); - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_BETT_NAME, key, 18); break; case SubmenuIndexCAMETwee: key = (key & 0x0FFFFFF0); key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54); break; case SubmenuIndexGateTX: key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?) uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); - generated_protocol = subghz_gen_data_protocol( + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexBeninca433: @@ -613,28 +613,28 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); + generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); + generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexLiftMaster_433_00: - generated_protocol = subghz_gen_secplus_v1_protocol(subghz->txrx, "AM650", 433920000); + generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 433920000); break; case SubmenuIndexSecPlus_v2_310_00: - generated_protocol = subghz_gen_secplus_v2_protocol( + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_315_00: - generated_protocol = subghz_gen_secplus_v2_protocol( + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_390_00: - generated_protocol = subghz_gen_secplus_v2_protocol( + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000); break; case SubmenuIndexSecPlus_v2_433_00: - generated_protocol = subghz_gen_secplus_v2_protocol( + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, "AM650", 433920000, key, 0x68, 0xE500000); break; default: diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index d5bd45618..305217f7d 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -26,7 +26,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { subghz_protocol_decoder_base_get_string( subghz_txrx_get_decoder(subghz->txrx), key_str); - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), @@ -66,7 +66,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); DOLPHIN_DEED(DolphinDeedSubGhzSend); @@ -82,7 +82,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { // Calling restore! subghz_txrx_stop(subghz->txrx); - if(!subghz_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index f4fc1aa94..ac6297d9e 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -51,14 +51,14 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) } } -void subghz_blink_start(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_start_magenta); +void subghz_blink_start(SubGhz* subghz) { + furi_assert(subghz); + notification_message(subghz->notifications, &sequence_blink_start_magenta); } -void subghz_blink_stop(SubGhz* instance) { - furi_assert(instance); - notification_message(instance->notifications, &sequence_blink_stop); +void subghz_blink_stop(SubGhz* subghz) { + furi_assert(subghz); + notification_message(subghz->notifications, &sequence_blink_stop); } SubGhz* subghz_alloc(bool alloc_for_tx_only) { @@ -262,7 +262,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { } if(!alloc_for_tx_only) { - subghz_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); + subghz_txrx_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); } subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); @@ -295,9 +295,9 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz->rpc_ctx = NULL; } - subghz_speaker_off(subghz->txrx); + subghz_txrx_speaker_off(subghz->txrx); subghz_txrx_stop(subghz->txrx); - subghz_sleep(subghz->txrx); + subghz_txrx_sleep(subghz->txrx); #if FURI_DEBUG // Packet Test diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 25e81725b..03aaa6da6 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -91,7 +91,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } furi_string_set_str( - temp_str, subghz_get_name_preset(subghz->txrx, furi_string_get_cstr(temp_str))); + temp_str, subghz_txrx_get_name_preset(subghz->txrx, furi_string_get_cstr(temp_str))); if(temp_str == NULL) { break; } @@ -112,7 +112,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } size_t preset_index = subghz_setting_get_inx_preset_by_name( subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); - subghz_set_preset( + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(temp_str), temp_data32, diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index a9594b789..82cc71752 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -43,7 +43,7 @@ #include "helpers/subghz_threshold_rssi.h" -#include "subghz_radio.h" +#include "helpers/subghz_txrx.h" #define SUBGHZ_MAX_LEN_NAME 64 #define SUBGHZ_EXT_PRESET_NAME true @@ -120,8 +120,8 @@ struct SubGhz { void* rpc_ctx; }; -void subghz_blink_start(SubGhz* instance); -void subghz_blink_stop(SubGhz* instance); +void subghz_blink_start(SubGhz* subghz); +void subghz_blink_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); From c69b2086b0942c3c1ccd3a233b26a8a13079178d Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 19:33:45 +0300 Subject: [PATCH 168/216] SubGhz: refactoring --- .../main/subghz/helpers/subghz_txrx.c | 5 +---- .../main/subghz/helpers/subghz_txrx.h | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 8 +------ .../scenes/subghz_scene_receiver_info.c | 5 ++--- applications/main/subghz/subghz.c | 12 ----------- applications/main/subghz/subghz_i.c | 21 +++++++++++++++++++ applications/main/subghz/subghz_i.h | 7 +++---- 7 files changed, 29 insertions(+), 31 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index c99b95e09..f400a1a52 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -355,12 +355,10 @@ void subghz_txrx_stop(SubGhzTxRx* instance) { case SubGhzTxRxStateTx: subghz_txrx_tx_stop(instance); subghz_txrx_speaker_unmute(instance); - //subghz_txrx_sleep(txrx); break; case SubGhzTxRxStateRx: subghz_txrx_rx_end(instance); subghz_txrx_speaker_mute(instance); - //subghz_txrx_sleep(txrx); break; default: @@ -439,7 +437,7 @@ void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance) { } } -void subghz_txrx_hopper_set_pause(SubGhzTxRx* instance) { +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { furi_assert(instance); if(instance->hopper_state == SubGhzHopperStateRunning) { instance->hopper_state = SubGhzHopperStatePause; @@ -522,7 +520,6 @@ bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* furi_assert(instance); furi_assert(name_protocol); bool res = false; - instance->decoder_result = NULL; instance->decoder_result = subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); if(instance->decoder_result) { diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index cb50e8334..c1ef132a4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -40,7 +40,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance); SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance); -void subghz_txrx_hopper_set_pause(SubGhzTxRx* instance); +void subghz_txrx_hopper_pause(SubGhzTxRx* instance); void subghz_txrx_speaker_on(SubGhzTxRx* instance); void subghz_txrx_speaker_off(SubGhzTxRx* instance); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 298ffda06..b7131e66e 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -140,13 +140,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { //Restore default setting if(subghz->raw_send_only) { - subghz_txrx_set_preset( - subghz->txrx, - "AM650", - subghz_setting_get_default_frequency( - subghz_txrx_get_setting(subghz->txrx)), - NULL, - 0); + subghz_set_defalut_preset(subghz); } else { subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 019898025..4e0e9e26f 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -117,13 +117,12 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { - //CC1101 Stop RX -> Start TX - subghz_txrx_hopper_set_pause(subghz->txrx); - if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } + //CC1101 Stop RX -> Start TX + subghz_txrx_hopper_pause(subghz->txrx); if(!subghz_txrx_tx_start( subghz->txrx, subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index ac6297d9e..4bf6e7aaf 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -51,16 +51,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) } } -void subghz_blink_start(SubGhz* subghz) { - furi_assert(subghz); - notification_message(subghz->notifications, &sequence_blink_start_magenta); -} - -void subghz_blink_stop(SubGhz* subghz) { - furi_assert(subghz); - notification_message(subghz->notifications, &sequence_blink_stop); -} - SubGhz* subghz_alloc(bool alloc_for_tx_only) { SubGhz* subghz = malloc(sizeof(SubGhz)); @@ -274,9 +264,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->secure_data = malloc(sizeof(SecureData)); subghz->filter = SubGhzProtocolFlag_Decodable; - subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); - subghz_txrx_need_save_callback_set(subghz->txrx, subghz_save_to_file, subghz); //Init Error_str diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 03aaa6da6..101ffdfdf 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,6 +18,27 @@ #define TAG "SubGhz" +void subghz_set_defalut_preset(SubGhz* subghz) { + furi_assert(subghz); + subghz_txrx_set_preset( + subghz->txrx, + "AM650", + subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + NULL, + 0); +} + +void subghz_blink_start(SubGhz* subghz) { + furi_assert(subghz); + notification_message(subghz->notifications, &sequence_blink_stop); + notification_message(subghz->notifications, &sequence_blink_start_magenta); +} + +void subghz_blink_stop(SubGhz* subghz) { + furi_assert(subghz); + notification_message(subghz->notifications, &sequence_blink_stop); +} + void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 82cc71752..e955d8360 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -120,32 +120,31 @@ struct SubGhz { void* rpc_ctx; }; +void subghz_set_defalut_preset(SubGhz* subghz); void subghz_blink_start(SubGhz* subghz); void subghz_blink_stop(SubGhz* subghz); void subghz_dialog_message_show_only_rx(SubGhz* subghz); + bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, const char* dev_file_name); - void subghz_save_to_file(void* context); - bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_file_available(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); bool subghz_path_is_file(FuriString* path); +SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); void subghz_lock(SubGhz* subghz); void subghz_unlock(SubGhz* subghz); bool subghz_is_locked(SubGhz* subghz); -SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz); - void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state); SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz); From 21cd94cc7953fefde53bf39058c5a0398e7c3849 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 19:50:01 +0300 Subject: [PATCH 169/216] SubGhz: show error tx start --- .../main/subghz/helpers/subghz_txrx.c | 32 ++++++++----------- .../main/subghz/helpers/subghz_txrx.h | 8 ++++- .../subghz/scenes/subghz_scene_read_raw.c | 2 +- .../scenes/subghz_scene_receiver_info.c | 4 +-- .../main/subghz/scenes/subghz_scene_rpc.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 7 ++-- applications/main/subghz/subghz_i.c | 17 ++++++++++ applications/main/subghz/subghz_i.h | 1 + 8 files changed, 47 insertions(+), 26 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index f400a1a52..c5118e67d 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -225,13 +225,13 @@ static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { return ret; } -bool subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { furi_assert(instance); furi_assert(flipper_format); subghz_txrx_stop(instance); - bool ret = false; + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; FuriString* temp_str = furi_string_alloc(); uint32_t repeat = 200; do { @@ -259,35 +259,31 @@ bool subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { instance, subghz_setting_get_preset_data_by_name( instance->setting, furi_string_get_cstr(instance->preset->name))); + if(instance->preset->frequency) { + if(!subghz_txrx_tx(instance, instance->preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } } else { FURI_LOG_E( TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(instance->preset->name)); - subghz_txrx_begin( - instance, - subghz_setting_get_preset_data_by_name(instance->setting, "AM650")); + ret = SubGhzTxRxStartTxStateErrorParserOthers; } - if(instance->preset->frequency) { - ret = subghz_txrx_tx(instance, instance->preset->frequency); - } else { - ret = subghz_txrx_tx(instance, 433920000); - } - if(ret) { + if(ret == SubGhzTxRxStartTxStateOk) { //Start TX furi_hal_subghz_start_async_tx( subghz_transmitter_yield, instance->transmitter); - } else { - //Todo: Show error - //subghz_dialog_message_show_only_rx(subghz); } } else { - //Todo: Show error - // dialog_message_show_storage_error( - // dialogs, "Error in protocol\nparameters\ndescription"); + ret = SubGhzTxRxStartTxStateErrorParserOthers; } } - if(!ret) { + if(ret != SubGhzTxRxStartTxStateOk) { subghz_transmitter_free(instance->transmitter); if(instance->txrx_state != SubGhzTxRxStateIDLE) { subghz_txrx_idle(instance); diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index c1ef132a4..4b7c28f3c 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -10,6 +10,12 @@ typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); typedef struct SubGhzTxRx SubGhzTxRx; +typedef enum { + SubGhzTxRxStartTxStateOk, + SubGhzTxRxStartTxStateErrorOnlyRx, + SubGhzTxRxStartTxStateErrorParserOthers, +} SubGhzTxRxStartTxState; + SubGhzTxRx* subghz_txrx_alloc(); void subghz_txrx_free(SubGhzTxRx* instance); bool subghz_txrx_is_load_database(SubGhzTxRx* instance); @@ -29,7 +35,7 @@ void subghz_txrx_get_frequency_modulation( FuriString* frequency, FuriString* modulation, bool long_name); -bool subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); void subghz_txrx_rx_start(SubGhzTxRx* instance); void subghz_txrx_stop(SubGhzTxRx* instance); void subghz_txrx_sleep(SubGhzTxRx* instance); diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index b7131e66e..f4749df65 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -209,7 +209,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); - if(!subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( subghz->subghz_read_raw, diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 4e0e9e26f..c92573e85 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -123,8 +123,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) //CC1101 Stop RX -> Start TX subghz_txrx_hopper_pause(subghz->txrx); - if(!subghz_txrx_tx_start( - subghz->txrx, + if(!subghz_tx_start( + subghz, subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { subghz_txrx_rx_start(subghz->txrx); subghz_txrx_hopper_remove_pause(subghz->txrx); diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 680eae7bc..70c909756 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -44,7 +44,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { bool result = false; if((subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateSleep) && (state == SubGhzRpcStateLoaded)) { - result = subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx)); + result = subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx)); if(result) subghz_blink_start(subghz); } if(!result) { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 305217f7d..72ba4ffc0 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -26,7 +26,8 @@ bool subghz_scene_transmitter_update_data_show(void* context) { subghz_protocol_decoder_base_get_string( subghz_txrx_get_decoder(subghz->txrx), key_str); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_modulation( + subghz->txrx, frequency_str, modulation_str, false); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), @@ -66,7 +67,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); DOLPHIN_DEED(DolphinDeedSubGhzSend); @@ -82,7 +83,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { // Calling restore! subghz_txrx_stop(subghz->txrx); - if(!subghz_txrx_tx_start(subghz->txrx, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 101ffdfdf..96b75e5b7 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -39,6 +39,23 @@ void subghz_blink_stop(SubGhz* subghz) { notification_message(subghz->notifications, &sequence_blink_stop); } +bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { + switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) { + case SubGhzTxRxStartTxStateErrorParserOthers: + dialog_message_show_storage_error( + subghz->dialogs, "Error in protocol\nparameters\ndescription"); + break; + case SubGhzTxRxStartTxStateErrorOnlyRx: + subghz_dialog_message_show_only_rx(subghz); + break; + + default: + return true; + break; + } + return false; +} + void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index e955d8360..b0157b672 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -124,6 +124,7 @@ void subghz_set_defalut_preset(SubGhz* subghz); void subghz_blink_start(SubGhz* subghz); void subghz_blink_stop(SubGhz* subghz); +bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); void subghz_dialog_message_show_only_rx(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog); From 752a11ba2644ead98ab4b420bafc3f3e1b9341b3 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 20:06:22 +0300 Subject: [PATCH 170/216] SubGhz: refactoring RPC --- applications/main/subghz/helpers/subghz_txrx.c | 5 ----- applications/main/subghz/helpers/subghz_txrx.h | 2 -- applications/main/subghz/scenes/subghz_scene_rpc.c | 11 +++++++---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index c5118e67d..f106df4f4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -362,11 +362,6 @@ void subghz_txrx_stop(SubGhzTxRx* instance) { } } -SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* instance) { - furi_assert(instance); - return instance->txrx_state; -} - void subghz_txrx_hopper_update(SubGhzTxRx* instance) { furi_assert(instance); diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 4b7c28f3c..667033d14 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -40,8 +40,6 @@ void subghz_txrx_rx_start(SubGhzTxRx* instance); void subghz_txrx_stop(SubGhzTxRx* instance); void subghz_txrx_sleep(SubGhzTxRx* instance); -SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* instance); - void subghz_txrx_hopper_update(SubGhzTxRx* instance); SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 70c909756..59497c493 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -7,6 +7,7 @@ typedef enum { SubGhzRpcStateIdle, SubGhzRpcStateLoaded, + SubGhzRpcStateTx, } SubGhzRpcState; void subghz_scene_rpc_on_enter(void* context) { @@ -42,9 +43,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateSleep) && - (state == SubGhzRpcStateLoaded)) { + if((state == SubGhzRpcStateLoaded)) { result = subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx)); + state = SubGhzRpcStateTx; if(result) subghz_blink_start(subghz); } if(!result) { @@ -56,9 +57,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; - if(subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateTx) { + if(state == SubGhzRpcStateTx) { subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); + state = SubGhzRpcStateIdle; result = true; } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); @@ -96,7 +98,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; - if(subghz_txrx_get_state(subghz->txrx) == SubGhzTxRxStateTx) { + SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); + if(state != SubGhzRpcStateIdle) { subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } From efe6dbf008a0005d11337e3339cbede547a58651 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 9 May 2023 18:11:05 +0100 Subject: [PATCH 171/216] Revert "Formatting" This reverts commit a441feec83d3482633640eae3829e0d13861465e. --- .../desktop/animations/animation_manager.c | 28 ++++++------------ .../desktop/animations/animation_storage.c | 17 +++++------ .../desktop/animations/animation_storage.h | 2 +- .../external/L3_Sunflower_128x64/frame_0.png | Bin 585 -> 0 bytes .../external/L3_Sunflower_128x64/frame_1.png | Bin 4838 -> 0 bytes .../external/L3_Sunflower_128x64/frame_2.png | Bin 5016 -> 0 bytes .../external/L3_Sunflower_128x64/frame_3.png | Bin 125 -> 0 bytes .../external/L3_Sunflower_128x64/frame_4.png | Bin 954 -> 0 bytes .../external/L3_Sunflower_128x64/frame_5.png | Bin 5139 -> 0 bytes .../external/L3_Sunflower_128x64/frame_6.png | Bin 1139 -> 0 bytes .../external/L3_Sunflower_128x64/meta.txt | 14 --------- assets/dolphin/external/manifest.txt | 7 ----- 12 files changed, 18 insertions(+), 50 deletions(-) delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_0.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_1.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_2.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_3.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_4.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_5.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/frame_6.png delete mode 100644 assets/dolphin/external/L3_Sunflower_128x64/meta.txt diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index 394ffee30..77884f2c1 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -217,25 +217,25 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager FS_Error sd_status = storage_sd_status(storage); if(sd_status == FSE_INTERNAL) { - blocking_animation = animation_storage_find_animation(BAD_SD_ANIMATION_NAME, false); + blocking_animation = animation_storage_find_animation(BAD_SD_ANIMATION_NAME); furi_assert(blocking_animation); } else if(sd_status == FSE_NOT_READY) { animation_manager->sd_shown_sd_ok = false; animation_manager->sd_shown_no_db = false; } else if(sd_status == FSE_OK) { if(!animation_manager->sd_shown_sd_ok) { - blocking_animation = animation_storage_find_animation(SD_OK_ANIMATION_NAME, false); + blocking_animation = animation_storage_find_animation(SD_OK_ANIMATION_NAME); furi_assert(blocking_animation); animation_manager->sd_shown_sd_ok = true; } else if(!animation_manager->sd_shown_no_db) { if(!storage_file_exists(storage, EXT_PATH("Manifest"))) { - blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME, false); + blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME); furi_assert(blocking_animation); animation_manager->sd_shown_no_db = true; animation_manager->sd_show_url = true; } } else if(animation_manager->sd_show_url) { - blocking_animation = animation_storage_find_animation(URL_ANIMATION_NAME, false); + blocking_animation = animation_storage_find_animation(URL_ANIMATION_NAME); furi_assert(blocking_animation); animation_manager->sd_show_url = false; } @@ -245,7 +245,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager DolphinStats stats = dolphin_stats(dolphin); furi_record_close(RECORD_DOLPHIN); if(!blocking_animation && stats.level_up_is_pending) { - blocking_animation = animation_storage_find_animation(NEW_MAIL_ANIMATION_NAME, false); + blocking_animation = animation_storage_find_animation(NEW_MAIL_ANIMATION_NAME); furi_check(blocking_animation); animation_manager->levelup_pending = true; } @@ -446,22 +446,12 @@ static StorageAnimation* /* cache animation, if failed - choose reliable animation */ if(selected == NULL) { FURI_LOG_E(TAG, "Can't find valid animation in manifest"); - selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME, false); + selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME); } else if(!animation_storage_get_bubble_animation(selected)) { const char* name = animation_storage_get_meta(selected)->name; FURI_LOG_E(TAG, "Can't upload animation described in manifest: \'%s\'", name); animation_storage_free_storage_animation(&selected); - selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME, false); - } else { - FuriHalRtcDateTime date; - furi_hal_rtc_get_datetime(&date); - if(date.month == 4 && date.day == 1 && furi_hal_random_get() % 2) { - animation_storage_free_storage_animation(&selected); - selected = animation_storage_find_animation("L3_Sunflower_128x64", true); - if(selected == NULL) { - selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME, false); - } - } + selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME); } furi_assert(selected); @@ -520,7 +510,7 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m if(animation_manager->state == AnimationManagerStateFreezedBlocked) { StorageAnimation* restore_animation = animation_storage_find_animation( - furi_string_get_cstr(animation_manager->freezed_animation_name), false); + furi_string_get_cstr(animation_manager->freezed_animation_name)); /* all blocked animations must be in flipper -> we can * always find blocking animation */ furi_assert(restore_animation); @@ -532,7 +522,7 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m if(!blocked) { /* if no blocking - try restore last one idle */ StorageAnimation* restore_animation = animation_storage_find_animation( - furi_string_get_cstr(animation_manager->freezed_animation_name), false); + furi_string_get_cstr(animation_manager->freezed_animation_name)); if(restore_animation) { Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); diff --git a/applications/services/desktop/animations/animation_storage.c b/applications/services/desktop/animations/animation_storage.c index 0905a6d43..b412d175b 100644 --- a/applications/services/desktop/animations/animation_storage.c +++ b/applications/services/desktop/animations/animation_storage.c @@ -30,11 +30,11 @@ static void animation_storage_free_frames(BubbleAnimation* animation); static void animation_storage_free_animation(BubbleAnimation** storage_animation); static BubbleAnimation* animation_storage_load_animation(const char* name); -void animation_handler_select_manifest(bool force_stock) { +void animation_handler_select_manifest() { XtremeSettings* xtreme_settings = XTREME_SETTINGS(); FuriString* anim_dir = furi_string_alloc(); FuriString* manifest = furi_string_alloc(); - bool use_asset_pack = !force_stock && xtreme_settings->asset_pack[0] != '\0'; + bool use_asset_pack = xtreme_settings->asset_pack[0] != '\0'; if(use_asset_pack) { furi_string_printf( anim_dir, "%s/%s/Anims", XTREME_ASSETS_PATH, xtreme_settings->asset_pack); @@ -61,10 +61,9 @@ void animation_handler_select_manifest(bool force_stock) { static bool animation_storage_load_single_manifest_info( StorageAnimationManifestInfo* manifest_info, - const char* name, - bool force_stock) { + const char* name) { furi_assert(manifest_info); - animation_handler_select_manifest(force_stock); + animation_handler_select_manifest(); bool result = false; Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); @@ -120,7 +119,7 @@ static bool animation_storage_load_single_manifest_info( void animation_storage_fill_animation_list(StorageAnimationList_t* animation_list) { furi_assert(sizeof(StorageAnimationList_t) == sizeof(void*)); furi_assert(!StorageAnimationList_size(*animation_list)); - animation_handler_select_manifest(false); + animation_handler_select_manifest(); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); @@ -176,7 +175,7 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis furi_record_close(RECORD_STORAGE); } -StorageAnimation* animation_storage_find_animation(const char* name, bool force_stock) { +StorageAnimation* animation_storage_find_animation(const char* name) { furi_assert(name); furi_assert(strlen(name)); StorageAnimation* storage_animation = NULL; @@ -203,8 +202,8 @@ StorageAnimation* animation_storage_find_animation(const char* name, bool force_ storage_animation->external = true; bool result = false; - result = animation_storage_load_single_manifest_info( - &storage_animation->manifest_info, name, force_stock); + result = + animation_storage_load_single_manifest_info(&storage_animation->manifest_info, name); if(result) { storage_animation->animation = animation_storage_load_animation(name); result = !!storage_animation->animation; diff --git a/applications/services/desktop/animations/animation_storage.h b/applications/services/desktop/animations/animation_storage.h index 55512e008..16c0feab4 100644 --- a/applications/services/desktop/animations/animation_storage.h +++ b/applications/services/desktop/animations/animation_storage.h @@ -61,7 +61,7 @@ void animation_storage_cache_animation(StorageAnimation* storage_animation); * @name name of animation * @return found animation. NULL if nothing found. */ -StorageAnimation* animation_storage_find_animation(const char* name, bool force_stock); +StorageAnimation* animation_storage_find_animation(const char* name); /** * Get meta information of storage animation. diff --git a/assets/dolphin/external/L3_Sunflower_128x64/frame_0.png b/assets/dolphin/external/L3_Sunflower_128x64/frame_0.png deleted file mode 100644 index 023da26d51428c1317946eb8e0f2e9cfd3134924..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 585 zcmV-P0=E5$P)pG`$F0X`QLUTXJjS=v6OKAX*>j<#Ruxla5 zJh2XtZy>-f%UO(C0URU{0Bx&046F-G0THKX9C~g0|0a> zqpR1u5CBs-mH^)d5w+N)6m(1wIEHXU7TW)_ju-%UtmhJJ3QNCP5;~kkVll z#RmeuQCCGRQ9%cEH6qL?pcow&7IZQrBI5XBzz2%1vhGbl#B#Q_tlIfUsyco9o^!r) z&Uene)wgrP!-Ab0COJS5mkr-pbs7EG00o9c7mn`hZ>MYb!)cC?M&bZhtWHRz(sOczUJG#@!U<@4DuG zvcGxkrWHcxxw$^s^Z%T-t8$!UI~g{vdswh>?u|Hn(E|vw`Gyn-!o>o?yM#a*J2Uh6 zA?N*FY8FO_^46>r?blrlFY4G!SzqBGI^?`4J9^4&YVV5aPU1Cd_qE2UAIpwEY;8MI zva$rW|Jv~PGaUCbAvtenIUtF?oX$GqvJJ*`!?h!fD-XrccIA$3ky6v$n3{7jpN*-p zZ(DuQ#Q5b)cc)uV(l$T~yV`s&zx{c)EF6h-v|oK;qYhAjntZ62UHdn!U4b#y#X}T*Xy$ zPdm+Ve0L#ntTC68E%FRlVLv=AGCW(78MP-r@lS%+;%QkIp3iERUW~GFt+QQp4K{xL z*ze`dqftAzcW(+5@9C*oJhRqtE`CpwdS{ocjx2({OKJ`6dYK|gc#+>76ufqdjo_#1 znzZ1E7lzAI61p#Kl>At@f|Z>(M(?*zRX^s^bd;0^f`I@8fZK{2^uU`GMgt;DX18(N+hUyg&K4o1o`^u)tD@W z(7}mB5~<`_lE>7{A>ENs90RRP|!(hE4 zRjK9a`4lTI4~#9-Gzx50(WUSyv666DpwbX9i^`&+h)7Q^VNhl|z`hz>&XWp*`XRs* zpOUQ8sd+S7dU`rFok>+`l4x`;mrFw#GzJ3!8i;nOQitggrPkE~(T5=3boY= zko|$Cj+DPA>x0-V5^Fkx0|Dj(xF2Z0%iXFBv?LOqP$f&VgeMmADHi`cTqPrMo^>cE z*eHQ{;|T7>B@hM*5@us{KDDhY5n-dr5#czYpi zE&(7=x)*}sbSA=gCXWfop>P&k0Xy*U_z0o*gVm<0-BBOE#l zLvVu4X31DACeD&sqrqjoAeBaefpU@xEQz40l}T2Cg>YU#xR_62P|^1@;i;HT4h;B| z*`zW}|6UMDDu@UjW?_@=#X(UP$eO`L84No2y;3xx(SlC2VA4@4lVz1y%EAN50Aevq zp8^2uJjjJ7&=8nTrHNFjQu!21NU+6nKr8{v3CDDp5YrI=6lE}ZD3izFM1ld!i-$5i zP&yACq_4tB`O^QTZCO09Z(qqnNGC-q9TaJeNTOlsibu&!LW5v@Gx0l3R-Ll z(N`>h)hCiAW6C4~>>mB?`fi^5jaIwZw!}V^h743 zkGuhNtxB#-$23Gh65tVV1=`cf75tU8Q0`XF2DH0KVF=1ZJ|>LTpD@j`XS~bU zm-Z1SzE*`nn+&k)n**B{*b8X`n_)j^AcEiX*I$d@(*+CysGxB;}#* z8lvly82BXRq3-&>(dF>|I7KMITTnVUEPY>KcNZMA>=I`M3#~^k=#{`|IrfiKhs@PN z(5Um4%cf3s2nUlRbYh8U#JyoI6R5UHvHMFQ$acM07!av9|GHDW348|-?I`HVB6?=T zQ`v#G7ZP6gMg{tR@p6(g=Yj7J&qkb`FzomFk{)DZViYAe-zuK4pC zc?sJ+Hky}LgnEoOC=!ZykWHq|Gb!eC>!Ag2k<65JUYjQf?DFFr+tTRGT3XSgq87)) zPCr9b$oG=1;fklfqE&j>k7948m#xV-(7fm5NhfOSUCvok!(Ow?ozT~Jnswx*i0Ad? z(z>{!F(l?5b2&GtxG;Xg9{D32iKZgvO-m~9=7KHL&7sbsgW1JTljmJJRQ^;m5pFDL zu67;E=TC~@#cn?xwdZ~K zDP44DZF6~vx5(vo^jYfRo^77DrWHm{A0wpL`-3ka&}Wb{)IU(U8BCs+8r@3f=Qldc z3X3%BNBl9?;MlpbER|apw@&ulaAejfbFtH_9m`u9mR8;ix!%~qi%8D9T{L>m+nW>o zjZc_?#?s7qT269l@?9zsa-!Wnf8O%Bon&d#@!HnB+uKH`tPk|8o;^0V+;g8frM;u@ zc3SqBM;g6P<>ZkW@i7;CvRqpxpFMNhzGr#)?A#vB-n4~b&xp#mF4D#Y#vHuj)I;IL zubS5WE4}b;k4@(n+lDVHhr zdiVIc-As?*@jnMnNt9>TU3=B}H+|&Do>#&zCADt3S&{@n4(q6(plEqe(9?uK8aq}M z%EC|0@~&MH8&bG2J7hO)jV|ff#Vn|F3;A^PvYdp8bJ>rxrn$>E=9ONbZ}=6jxP85C zUs-k;?7BMh$T6|cvG5K35pIaeUwr3G)yhp(=FFyjytB9EP_gcVqPUpG8;P~Y6GwQ| zy0+z78+reo>f_$powf;D($(hQ(EsB{cr>D9xaQWps(xS8?cCkCM{Bq?ebk|Y`^J1U zHtKykuq~|IchZSe_R$%?HXbNC+cP9pj2P)bn2^FpLZ$PVGu>c+BcYbY1cwen zfHxU4nWha=6g8X8Y%`y&H)>F>L?S^sJe0>nfCXY&p`$SiqBF5<5Ca&&qzN}t2Ab0A zU>hc;(x=ffCKKr4r}1eG3dIn-&NRpZ-~+W_29(R@pjs_D+`~kNqyvz_fd16O6bIHR z8bg}&X-1q3NhftQYd8df5BVF?j4AeX2plC-NG&imfmylFO&KOvL=Sn`D9}(^gWU^| z{hTFDsh^ScTx>RtJ)Pl!0QVu>=d7RRZZ`&23WYRSkEhwflLyO~w)v%m9;XPY{gEq{ zV17KV1R+F1KSUrA3K22iPl8|^LP&BYDgpQpgOck^G^WEz8x#O%QvgSR3kac@@I!a97$_&D#WW;p&}r-n8{yKxXt|8ZV{@KKqEj$h4IE_5 zxs)!=@=Os&X~|d`v$4q)i8&krUnutT6Nn@t@iU_Y(r5ymXv5@k*nELqV=IdkBm;=W zY<&s<>~fHcG{{I|wB8t}*Qdyswvb?(=a5=xB~5I=L&w)UMQdEV=*U_wkiO^5Dp*tBVp)Z!l-S}c$%?4 z`Ug(@?FPd(8Q?b{1DhAv3(=v?aF8<)??3q)ti?Y$1q{EOF7-zZCxv)jo0W%oQPx?{Qq=Lh{ z%2Ax{Ay@B?|LS!{g^QPW@@JJ7vn@#E=b0nma474qhqk2q`2zMQk9^81pKNL9GS^!9 z9Zw#8ax?t>-smXKy#5M zRZmygTXnH^EOiU^UB%Qhf24CE&dy=?kn;4NL~l=pSbk5&GcQiL%BdYTeM$KDZk709iJLi z6*@0rG2?&ktma*eMKwvA_8^|sO=FO0)dvnd+*Q#*^KT(75o*WmBY7E)ZP=vD%a@&Y zK3u(fb;8As-HXOuQ0IRZHfqP-x{S;e|8sYKN!-s$U)Zv6%JhY!``*cXGjc)Q>-xg& zbsm0Vd!PA2!4`!vR`n-;NWZKbi{#uQ$mv8H-iXH&`C z^trdTB`!z5y%jrQEsMh9#vco^TJvL$CrFCZzRVT)ZY{WFU4FM{TxsZ)Wkms7h~y`* z=aPH>{@721mTt5bAB}XKemd2AT+!C5j2w@nzUrkHefQn=y3^HvzSn0C;qcw@(;=Gl zgo?x&o`;BB;;hp9gD(yixvH4Cu!HNE%;7`s_R+J{AGDJ$8e`9>j}2+$zq$P*MFjzy8QC>{QyhUs{}ZzTSGvsYuBR?d$ns#o9w> zZZ&6z_@!TYP#9SKw6zGwQsUEg&*YYOHN&MJHV}by62|q&Eolc=l!VHK&sJY z{TKO4vx~6rX5E2;ZAppW3no?`T6lM{M}_RYl^@1`yH~TlXN_xM)H!8EGyllm>({vI zD94XGOQn3m(yN|${f9Px$di}5ep=SotoE7+-r61roel*$j-LAb(9r$b{da!1ctBAs P+v<~tLpIY)M2xRCwC$T-kC2AqbrR|LLSEPg~>IbOX9Ffv33ZdT`l*=DM1i znwpxLnwpxLnwpxLnwpxLn#$47AAL4gPgivCRV%xFmAi+VbR*-BKV&{BFMzRWZX3^q ztqpw3%v(kPc%Qd#L6hl#S&W;eF}Y>Go9U7^eXf<+ByV1(08}*spPXwA(ymAgNO3H; zp>UJ5i5h3X$RNCJRREy#I2SpQsR~CQ3B15aEsOYKiA|%2kw&X`O0V#<5gwUSFGbZy zxU4uAq-JpH8lkW07O;J|e=Z5&aiT1hPZry3t!|tXInuEQli*V%B2jm}Fuj9We6w-W zTq3~~*?e3HzY$00G$%e{%Ewcb$J%ba1L8D0-y9toBt{fvlK^Ia%(wt#2Kr+ULvnn? z_@q+v(pq@Zj@uY_4m#if2k7|YASU7di~?b8W2BXN2tNW9Q#QajOs>t4$xN1vet<~< zyD<|OP`ey%;>7{gHq$sb$AG5;LL$9687Hp|8W^NSdiF=(qT)+Z9+E1UYx`zqf{`{5 zKqT6nxgcIERn7IOe181pt`=ZkW8LRRi=^si5ZScL+L`bvDhsiYPXM#n zod-Nj1%fXF@V<^gpIf1nFX?LP@5}}H>IACQ@2p8I4}eX)!T%O`C-UbJY@LXnzmH}4 zcoMsslrR|NN*Ux@gQPq}ZX{@0WMnZr@7Zt4)0yE6Q)y76yc7YH;W(&p@fSvdE=av! zQr{DRVl~-^H@Kq(Fgt-sJvGzU=ACuEcF*%2k9>p-m`mPFL@FJd z(g6z;->fM~wSlAa)fabZz>)oq=ctPvztUELQ&!&|1wnz7RId~YWa+FFW=kt!{9&c{ zk!p&9Zzh%=*QF{8Ka%O~HT#_FJZoRPbCB+Im>^YMWF(<~v<&z>fmAti9D~x-?=fZR z{h~XAlo)fo?d;j+f-bR0l9)QK`d=b8yPzzMW}fQ30Z~W~fG+ximt*RG6d43xogW*H cHNA~~0pP;2~&b^rhX07*qoM6N<$f*XdkM*si- diff --git a/assets/dolphin/external/L3_Sunflower_128x64/frame_5.png b/assets/dolphin/external/L3_Sunflower_128x64/frame_5.png deleted file mode 100644 index e8303b575e8f147ca2432c5cad493e6496618f24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5139 zcmeHKdpMM78y~SHm6b{d+TI+rw10A;HduOP0?OxaSbzR^7*Id_odY<3?d+z)9-1mLW zlg3-&HO*q41qy|l#_?wRA3G^^X43uBXY&O%s1?4LG@FGM@JNZ_m%J`>hG!Bx8zu zGc^unVHsCyx|iP1D~x`y$NFD68}-iS{!%yay4_MpdVO5YXxY81+3ib+fx>v-&=*J1kCrv3@15G<81rp(5+zAL*eoMTiqqa z$;E(qLgML4nscRh+K7(@C~&1cxLg&tqbep*UqWc?=b&;G`}Xqv8hQh3s{_rZ*P3^y z);AFT?chA^=A)<`sC5I~u2)BXEfDg+psD7mmnMt%P##Tu)bO2L)#YS)@$rrHem1ABj2R^048Dy^ReszD}$4o4q)+;mUW*T)B4sgSGU zJ=m$U2D9MOmhI>iPZ#$j^G~AqycBNysspE^@Bg{)Z}0ub5t}sHw?qUlX_B$frxQE0^CyP5QbK&_w{bN_~g|QJrx(MyI#KKj_KnUcp76No~ znL@+RG0{d|2J&tg#-afuL>s|G2XT1-OR0td5{87qfu1^PGy%QD0&rD}#0)?7vM~ze zi-``?YE=v@HYO$p6GOx()e*18@A3tGL{^^a{38y|pk%Ad$*d zMk_?@_mEnt_?=kq`DU0ghBMv~#QZJqd+0Z@8^H*Q%Vn^Y!YG4#95xeeSf3$M3Z){3 z@f9y1lVF;F2tp8v4w7&}2&9okc#tlH=mZLtK&6sMU&TfEPm`i9#lWbR3Ne!W5c_D5ld0M4EUU#Y(jl$x28z-YWx@2%&;#A}UQR#)B|S z7Jwu&g$6<}4F&~bI$cZ_&>*T1XQUDd8OxMvIfQJdR1QgCtV$sH20|`WLAHlVFNKL?MABnve*RNCGNI zhp9x6MkC;H6g-uVhp6wfYm{Pb45WtLC5VoQR!DjpwE`9zH_G{abW9j**abu|5Jv?6 zEEskyV635MyouNq`zK9Yjev1Y2C*9*Lz)-T3$bsT;h1KIw(~ds#`fZGTmhl}xX1_T z`%$isa($2j9|ZoGT_5H8AO$`M{4u-!Z*p0@J5Iq0a#*spAI;shtgmNZEQg3xzVRHm5=n~!Rb zO1XNc;MM9E&wK}U68X)*bo%AcHTa^zGo^Q*Ty-8E-tX4Z@0suA*b>gl?d$vU3FUEQ zPJG{^(nA%A>IqiaIUP04R>3cO1wBK4%SYl5$2PxwJn#bjI=|g2cG6EHcYPv)bYS&`%52WWxg_vApLx*Jm`|g3B)%w&yRH1a zy#%~{LxT^nRi%c@zdGk+8+UPXq9rfWjyu$w8I+xof6)4C87q71lc$?RRZZJ3UuXZL z+{9|AeYv9?A6Fg2-sg1ir)e7}bS011N0L|7i7&%Pn?#(c3nMnS&2c4Ttp`e((PzDEo)NuDkrX=`DrYum$!_ z9&+`$%I4>X6Jn=qF^faT@9m!WE$@`yCB6MR`RTdCZu7d++4o#4W`qVc?hlzaY0kNv z9KXQqll@r|RPdK;7q<1!M$gG0WCGr|!)DdLJV}q8-(J{Ub)w){hjfo^>Sy&~ky`eN zSi4uPb2g`zmCxBVeT}^!=qX{skvfyY&s#%1W`>oTWPTbcvs)j~DzDJX8q;oa);m1x zJuUH0|H8Ar>soUF|HP>+Hmx*PviP6ZC!GDH#fEyKFQ8||%P!&hw*F^8o6ANCrh0Z~ zF{fF^AvAtr!*xvSp+3kpBY2t~sPk_bsB6swqtGfaZt19mF&-X#` zYYUH72V}J!4J{s7^}4)iAnV2jJyfU@o+|eMU?NCwNtj9-kkqOtIO-XYf=5_ zx=G}gpYECuOx??CzP0>?`P|^L^cGD${5^QN&f+6mcqjT diff --git a/assets/dolphin/external/L3_Sunflower_128x64/frame_6.png b/assets/dolphin/external/L3_Sunflower_128x64/frame_6.png deleted file mode 100644 index aaaa2a5cdfcf7c706c97b62845cdbaba432442f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1139 zcmV-(1dRKMP)pJB}qg5uF1Ssvc3M~hJgONbcR3wq3 zP&8_Q0!9+W#49gEB0&RfIsHy=G``NzX4>5?OSgw@`@MNCNV7BjX5O6x-_F+IAdyJr zlC$2Tb&>&OKzZB5Rs0jPRk3nLrPtexLk5rmWmJ#98~pkEJICtkOJJs#QmGRlmu=;; zGEu1E0Fdj9Mu&l!vWtuJKrY+HW$Wq7@9zP51|*h%nX<>nzkpoU&1EH?;b;WNb;d@9 zfr&xmm|u7S^bBy40c3zd*j-(nKn^;Gi>q)NX3WQ>Tg18nce!*cZ|Bk$332Hb$xey( zor0WRuCud@Hu{h{0D{4R+${!z!NAbaeIQ?%PM?6&(=_99P_j)^46U)G;Z8BryF@OP7iFkymisC&<{RC#>dHe1)KohJlMPxwp8IaT5 z+zVi)!Qn^&C| zZ#r)zqewED6v(9!OUoqM#{lQT!W=L&=SCu7Q0b74jt+sDcoK;fQ12sv45*PrrX?I! zKkV)R?Ie48mICtUlT(jDB%)Sg;EN=css^G%dQ=I2G|<^>pK}udjdG{|e-0#N$snarye`>8Y8SIFPU0+S&xk z|I6Z|i2%$pA7y(rqq-q~p~# zzo1)12D|73nbJMz>+1!&m3z1f{%e84;XzQR4`dwvJ3T-S`qSPn=OiSGEV)OUp<71$j zmJ1Zc2cWutAEx9ksOCFjMZ##7jVT$>oCXvgXCnh>1dst_fXCx$ZEXS74?~|USt3nP^k@x&0?a=G>KFL{R5*6#PriTRQdn_002ovPDHLk FV1g;35jFq- diff --git a/assets/dolphin/external/L3_Sunflower_128x64/meta.txt b/assets/dolphin/external/L3_Sunflower_128x64/meta.txt deleted file mode 100644 index f93fdaae7..000000000 --- a/assets/dolphin/external/L3_Sunflower_128x64/meta.txt +++ /dev/null @@ -1,14 +0,0 @@ -Filetype: Flipper Animation -Version: 1 - -Width: 128 -Height: 64 -Passive frames: 16 -Active frames: 0 -Frames order: 0 1 2 3 4 5 5 5 6 6 6 6 6 6 3 3 -Active cycles: 0 -Frame rate: 1 -Duration: 360 -Active cooldown: 0 - -Bubble slots: 0 diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 52cc88a7e..f9303a6ff 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -133,10 +133,3 @@ Max butthurt: 10 Min level: 27 Max level: 30 Weight: 3 - -Name: L3_Sunflower_128x64 -Min butthurt: 0 -Max butthurt: 14 -Min level: 1 -Max level: 30 -Weight: 0 From 42a415e4490b02b006539ee565bd6a1cfc8240b1 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 20:19:01 +0300 Subject: [PATCH 172/216] SubGhz: value get optimizations --- .../subghz/scenes/subghz_scene_read_raw.c | 2 +- .../scenes/subghz_scene_receiver_config.c | 71 ++++++++----------- .../subghz/scenes/subghz_scene_transmitter.c | 10 +-- applications/main/subghz/subghz_i.c | 2 +- applications/main/subghz/subghz_i.h | 2 +- 5 files changed, 37 insertions(+), 50 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index f4749df65..e7e93ad24 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -140,7 +140,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { //Restore default setting if(subghz->raw_send_only) { - subghz_set_defalut_preset(subghz); + subghz_set_default_preset(subghz); } else { subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index d65778b01..3edde712e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -93,15 +93,14 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; - i < subghz_setting_get_frequency_count(subghz_txrx_get_setting(subghz->txrx)); - i++) { - if(value == subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), i)) { + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) { + if(value == subghz_setting_get_frequency(setting, i)) { index = i; break; } else { - index = - subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); + index = subghz_setting_get_frequency_default_index(setting); } } return index; @@ -111,15 +110,14 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* furi_assert(context); SubGhz* subghz = context; uint8_t index = 0; - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz_txrx_get_setting(subghz->txrx)); - i++) { - if(!strcmp( - subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), i), - preset_name)) { + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) { + if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) { index = i; break; } else { - // index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx)); + // index = subghz_setting_get_frequency_default_index(setting); } } return index; @@ -148,6 +146,7 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; @@ -155,10 +154,8 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index) / 1000000, - (subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index) % - 1000000) / - 10000); + subghz_setting_get_frequency(setting, index) / 1000000, + (subghz_setting_get_frequency(setting, index) % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); @@ -166,19 +163,17 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), - subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), index), + subghz_setting_get_frequency(setting, index), preset.data, preset.data_size); preset = subghz_txrx_get_preset(subghz->txrx); subghz->last_settings->frequency = preset.frequency; - subghz_setting_set_default_frequency( - subghz_txrx_get_setting(subghz->txrx), preset.frequency); + subghz_setting_set_default_frequency(setting, preset.frequency); } else { variable_item_set_current_value_index( - item, - subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); + item, subghz_setting_get_frequency_default_index(setting)); } } @@ -202,42 +197,34 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig); variable_item_set_current_value_text(item, hopping_text[index]); if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_default_frequency(setting); snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)) / 1000000, - (subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)) % - 1000000) / - 10000); - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - text_buf); + frequency / 1000000, + (frequency % 1000000) / 10000); + variable_item_set_current_value_text(frequency_item, text_buf); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), - subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)), + frequency, preset.data, preset.data_size); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } else { - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - " -----"); + variable_item_set_current_value_text(frequency_item, " -----"); variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx))); + frequency_item, subghz_setting_get_frequency_default_index(setting)); } subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]); @@ -411,8 +398,8 @@ void subghz_scene_receiver_config_on_enter(void* context) { SPEAKER_COUNT, subghz_scene_receiver_config_set_speaker, subghz); - value_index = - value_index_uint32(subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); + value_index = value_index_uint32( + subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, speaker_text[value_index]); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 72ba4ffc0..c1bbd2343 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -15,16 +15,16 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; bool ret = false; - if(subghz_txrx_get_decoder(subghz->txrx)) { + SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx); + + if(decoder) { FuriString* key_str = furi_string_alloc(); FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); if(subghz_protocol_decoder_base_deserialize( - subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx)) == - SubGhzProtocolStatusOk) { - subghz_protocol_decoder_base_get_string( - subghz_txrx_get_decoder(subghz->txrx), key_str); + decoder, subghz_txtx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { + subghz_protocol_decoder_base_get_string(decoder, key_str); subghz_txrx_get_frequency_modulation( subghz->txrx, frequency_str, modulation_str, false); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 96b75e5b7..d17c6858f 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -18,7 +18,7 @@ #define TAG "SubGhz" -void subghz_set_defalut_preset(SubGhz* subghz) { +void subghz_set_default_preset(SubGhz* subghz) { furi_assert(subghz); subghz_txrx_set_preset( subghz->txrx, diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index b0157b672..785a6708f 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -120,7 +120,7 @@ struct SubGhz { void* rpc_ctx; }; -void subghz_set_defalut_preset(SubGhz* subghz); +void subghz_set_default_preset(SubGhz* subghz); void subghz_blink_start(SubGhz* subghz); void subghz_blink_stop(SubGhz* subghz); From 02a22086a1cc2fcb4baa03f1847bccb98e620194 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 9 May 2023 20:21:07 +0300 Subject: [PATCH 173/216] Update changelog and change mfkey category --- CHANGELOG.md | 25 ++++++++----------- applications/external/mfkey32/application.fam | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 459a9d6c2..bd3ff9a6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,14 @@ ### New changes -* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues! -* Plugins: RFID and iButton Fuzzer remove excessive free's (thanks @Willy-JL) -* Plugins: Use COUNT_OF in mouse jiggler -* Plugins: Added Numpad keyboard to HID app (by @clipboard1 | PR #452) -* About: Don't show 00 on about screens -* SubGHz: Combine FuriString allocs and other small changes -* Infrared: Updated universal remote assets (by @amec0e | PR #454) -* Update slideshow: Replace QR code with good old link -* OFW: Various Furi/FuriHal bug fixes and improvements -> **Breaking API change, api was changed from 24.x to 26.x** -* OFW: Loader refactoring, part 1 -> **Breaking API change, api was changed from 23.x to 24.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** -* OFW: Dolphin builder in ufbt; minor ufbt/fbt improvements -* OFW: Added API version to device info -* OFW: Gui: relax some asserts in view -* OFW: Move gauge calibration to separate header, add f18 calibration -* OFW: Fix TERMINFO on Linux systems +* Extra pack: Some app fixes +* OFW: ble: attempt to handle hardfaulted c2 +* OFW: Add Mfkey32 application +* OFW: Added DigitalSequence and PulseReader +* OFW: Debug: revert cortex debug to lxml and drop DWT **(reapply your VSCode launch.json from example folder)** +* OFW: furi_crash: added C2 status; added fw-version gdb command +* OFW: Removed STM32CubeWB module +* OFW: API version in UI +* OFW: ufbt: deploying sample ufbt automation for new apps; added `source "ufbt -s env"` for toolchain access +* OFW: Fix storage.py exist_dir logic #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/applications/external/mfkey32/application.fam b/applications/external/mfkey32/application.fam index 9a9cbf581..eb11aec2c 100644 --- a/applications/external/mfkey32/application.fam +++ b/applications/external/mfkey32/application.fam @@ -10,7 +10,7 @@ App( ], stack_size=1 * 1024, fap_icon="mfkey.png", - fap_category="Nfc", + fap_category="Tools", fap_author="noproto", fap_icon_assets="images", fap_weburl="https://github.com/noproto/FlipperMfkey", From 1d2d05cfdfb39b864910c1c5b473648cb05d4c92 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 9 May 2023 20:24:43 +0300 Subject: [PATCH 174/216] Fix merge issues --- scripts/version.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/version.py b/scripts/version.py index aec480b2e..27772e9c2 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -35,8 +35,6 @@ class GitVersion: or "unknown" ) - branch_num = self._exec_git("rev-list --count HEAD") or "n/a" - version = ( os.environ.get("DIST_SUFFIX", None) or "unknown" @@ -58,7 +56,6 @@ class GitVersion: return { "GIT_COMMIT": commit, "GIT_BRANCH": branch, - "GIT_BRANCH_NUM": branch_num, "FURI_CUSTOM_FLIPPER_NAME": custom_fz_name, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, @@ -67,7 +64,6 @@ class GitVersion: return { "GIT_COMMIT": commit, "GIT_BRANCH": branch, - "GIT_BRANCH_NUM": branch_num, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, } From def4ae395ea64e8e5bee31740344d2a0a14b89d8 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 21:20:35 +0300 Subject: [PATCH 175/216] SubGhz: refactoring --- .../main/subghz/helpers/subghz_txrx.c | 410 +----------------- .../main/subghz/helpers/subghz_txrx.h | 86 +--- .../subghz/helpers/subghz_txrx_callbacks.h | 2 + .../helpers/subghz_txrx_create_potocol_key.c | 346 +++++++++++++++ .../helpers/subghz_txrx_create_potocol_key.h | 87 ++++ .../main/subghz/helpers/subghz_txrx_i.h | 34 ++ .../subghz/scenes/subghz_scene_need_saving.c | 7 +- .../subghz/scenes/subghz_scene_read_raw.c | 52 +-- .../subghz/scenes/subghz_scene_receiver.c | 24 +- .../scenes/subghz_scene_receiver_config.c | 38 +- .../subghz/scenes/subghz_scene_set_seed.c | 1 + .../subghz/scenes/subghz_scene_set_type.c | 44 +- 12 files changed, 573 insertions(+), 558 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_txrx_callbacks.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c create mode 100644 applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h create mode 100644 applications/main/subghz/helpers/subghz_txrx_i.h diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index f106df4f4..38cf549de 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,34 +1,9 @@ +#include "subghz_txrx_i.h" #include "subghz_txrx.h" #include #define TAG "SubGhz" -struct SubGhzTxRx { - SubGhzWorker* worker; - - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; - SubGhzProtocolDecoderBase* decoder_result; - FlipperFormat* fff_data; - - SubGhzRadioPreset* preset; - SubGhzSetting* setting; - - uint8_t hopper_timeout; - uint8_t hopper_idx_frequency; - bool load_database; - SubGhzHopperState hopper_state; - - SubGhzTxRxState txrx_state; - SubGhzSpeakerState speaker_state; - - SubGhzTxRxNeedSaveCallback need_save_callback; - void* need_save_context; - - bool debug_pin_state; -}; - SubGhzTxRx* subghz_txrx_alloc() { SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); instance->setting = subghz_setting_alloc(); @@ -98,9 +73,10 @@ void subghz_txrx_set_preset( size_t preset_data_size) { furi_assert(instance); furi_string_set(instance->preset->name, preset_name); - instance->preset->frequency = frequency; - instance->preset->data = preset_data; - instance->preset->data_size = preset_data_size; + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; } const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset) { @@ -133,18 +109,19 @@ void subghz_txrx_get_frequency_modulation( FuriString* modulation, bool long_name) { furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; if(frequency != NULL) { furi_string_printf( frequency, "%03ld.%02ld", - instance->preset->frequency / 1000000 % 1000, - instance->preset->frequency / 10000 % 100); + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); } if(modulation != NULL) { if(long_name) { - furi_string_printf(modulation, "%s", furi_string_get_cstr(instance->preset->name)); + furi_string_printf(modulation, "%s", furi_string_get_cstr(preset->name)); } else { - furi_string_printf(modulation, "%.2s", furi_string_get_cstr(instance->preset->name)); + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); } } } @@ -247,20 +224,22 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* FURI_LOG_E(TAG, "Unable Repeat"); break; } + ret = SubGhzTxRxStartTxStateOk; + SubGhzRadioPreset* preset = instance->preset; instance->transmitter = subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); if(instance->transmitter) { if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == SubGhzProtocolStatusOk) { - if(strcmp(furi_string_get_cstr(instance->preset->name), "") != 0) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { subghz_txrx_begin( instance, subghz_setting_get_preset_data_by_name( - instance->setting, furi_string_get_cstr(instance->preset->name))); - if(instance->preset->frequency) { - if(!subghz_txrx_tx(instance, instance->preset->frequency)) { + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { FURI_LOG_E(TAG, "Only Rx"); ret = SubGhzTxRxStartTxStateErrorOnlyRx; } @@ -269,9 +248,7 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* } } else { FURI_LOG_E( - TAG, - "Unknown name preset \" %s \"", - furi_string_get_cstr(instance->preset->name)); + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); ret = SubGhzTxRxStartTxStateErrorParserOthers; } if(ret == SubGhzTxRxStartTxStateOk) { @@ -533,17 +510,15 @@ bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance) { bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type) { furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; if(check_type) { return ( - ((instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - instance->decoder_result->protocol->encoder->deserialize && - instance->decoder_result->protocol->type == SubGhzProtocolTypeStatic); + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); } return ( - ((instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == - SubGhzProtocolFlag_Send) && - instance->decoder_result->protocol->encoder->deserialize); + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); } void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { @@ -581,345 +556,4 @@ bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { furi_assert(instance); return instance->receiver; -} - -//#############Create new Key############## -#include -#include -#include -#include -#include - -#include -#include -#include - -bool subghz_txrx_gen_data_protocol( - void* context, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit) { - furi_assert(context); - SubGhzTxRx* instance = context; - - bool res = false; - - subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); - instance->decoder_result = - subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); - - if(instance->decoder_result == NULL) { - //TODO: Error - // furi_string_set(error_str, "Protocol not\nfound!"); - // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); - return false; - } - - do { - Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); - stream_clean(fff_data_stream); - if(subghz_protocol_decoder_base_serialize( - instance->decoder_result, instance->fff_data, instance->preset) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Unable to serialize"); - break; - } - if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { - FURI_LOG_E(TAG, "Unable to update Bit"); - break; - } - - uint8_t key_data[sizeof(uint64_t)] = {0}; - for(size_t i = 0; i < sizeof(uint64_t); i++) { - key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; - } - if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Unable to update Key"); - break; - } - res = true; - } while(false); - return res; -} - -bool subghz_txrx_gen_data_protocol_and_te( - SubGhzTxRx* instance, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t te) { - furi_assert(instance); - bool ret = false; - if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { - if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { - FURI_LOG_E(TAG, "Unable to update Te"); - } else { - ret = true; - } - } - return ret; -} - -bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename - SubGhzTxRx* txrx, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name) { - furi_assert(txrx); - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_keeloq_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - manufacture_name, - txrx->preset)) { - flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", manufacture_name); - res = true; - } - subghz_transmitter_free(txrx->transmitter); - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name) { - SubGhzTxRx* txrx = context; - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - seed, - manufacture_name, - txrx->preset)) { - res = true; - } - - if(res) { - 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] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - - flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", "BFT"); - } - - subghz_transmitter_free(txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - bool nice_one) { - SubGhzTxRx* txrx = context; - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - txrx->preset, - nice_one)) { - res = true; - } - - subghz_transmitter_free(txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name) { - SubGhzTxRx* txrx = context; - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_faac_slh_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - seed, - manufacture_name, - txrx->preset)) { - res = true; - } - - if(res) { - 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] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - } - - subghz_transmitter_free(txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt) { - SubGhzTxRx* txrx = context; - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - txrx->preset)) { - res = true; - } - - subghz_transmitter_free(txrx->transmitter); - - return res; -} - -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt) { - SubGhzTxRx* txrx = context; - - bool res = false; - - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); - subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); - - if(txrx->transmitter && subghz_protocol_somfy_telis_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - txrx->preset)) { - res = true; - } - - subghz_transmitter_free(txrx->transmitter); - - return res; -} - -bool subghz_txrx_gen_secplus_v2_protocol( - SubGhzTxRx* txrx, - const char* name_preset, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint32_t cnt) { - furi_assert(txrx); - - bool ret = false; - txrx->transmitter = - subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); - subghz_txrx_set_preset(txrx, name_preset, frequency, NULL, 0); - if(txrx->transmitter) { - subghz_protocol_secplus_v2_create_data( - subghz_transmitter_get_protocol_instance(txrx->transmitter), - txrx->fff_data, - serial, - btn, - cnt, - txrx->preset); - ret = true; - } - return ret; -} - -bool subghz_txrx_gen_secplus_v1_protocol( - SubGhzTxRx* txrx, - const char* name_preset, - uint32_t frequency) { - furi_assert(txrx); - - bool ret = false; - uint32_t serial = (uint32_t)rand(); - while(!subghz_protocol_secplus_v1_check_fixed(serial)) { - serial = (uint32_t)rand(); - } - if(subghz_txrx_gen_data_protocol( - txrx, - name_preset, - frequency, - SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, - (uint64_t)serial << 32 | 0xE6000000, - 42)) { - ret = true; - } - return ret; } \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 667033d14..590fcd4f4 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -1,5 +1,6 @@ #pragma once #include "subghz_types.h" +#include "subghz_txrx_callbacks.h" #include #include #include @@ -80,88 +81,3 @@ void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state); bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance); SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw - -//#############Create new Key############## -bool subghz_txrx_gen_data_protocol( - void* context, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit); - -bool subghz_txrx_gen_data_protocol_and_te( - SubGhzTxRx* instance, - const char* preset_name, - uint32_t frequency, - const char* protocol_name, - uint64_t key, - uint32_t bit, - uint32_t te); - -bool subghz_scene_set_type_submenu_gen_data_keeloq( - SubGhzTxRx* txrx, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - bool nice_one); - -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - uint32_t seed, - const char* manufacture_name); - -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt); - -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename - void* context, - const char* preset_name, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint16_t cnt); - -bool subghz_txrx_gen_secplus_v2_protocol( - SubGhzTxRx* txrx, - const char* name_preset, - uint32_t frequency, - uint32_t serial, - uint8_t btn, - uint32_t cnt); - -bool subghz_txrx_gen_secplus_v1_protocol( - SubGhzTxRx* txrx, - const char* name_preset, - uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_callbacks.h b/applications/main/subghz/helpers/subghz_txrx_callbacks.h new file mode 100644 index 000000000..5bee720e9 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_callbacks.h @@ -0,0 +1,2 @@ +#pragma once +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c new file mode 100644 index 000000000..7c3b1c7ff --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c @@ -0,0 +1,346 @@ +#include "subghz_txrx_i.h" +#include "subghz_txrx_create_potocol_key.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TAG "SubGhzCreateProtocolKey" + +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit) { + furi_assert(context); + SubGhzTxRx* instance = context; + + bool res = false; + + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name); + + if(instance->decoder_result == NULL) { + //TODO: Error + // furi_string_set(error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub); + FURI_LOG_E(TAG, "Protocol not found!"); + return false; + } + + do { + Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data); + stream_clean(fff_data_stream); + if(subghz_protocol_decoder_base_serialize( + instance->decoder_result, instance->fff_data, instance->preset) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Unable to serialize"); + break; + } + if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) { + FURI_LOG_E(TAG, "Unable to update Bit"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + break; + } + res = true; + } while(false); + return res; +} + +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te) { + furi_assert(instance); + bool ret = false; + if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) { + if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) { + FURI_LOG_E(TAG, "Unable to update Te"); + } else { + ret = true; + } + } + return ret; +} + +bool subghz_txrx_gen_keelog_protocol( //TODO lead to a general appearance + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name) { + furi_assert(instance); + + bool res = false; + + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0); + + if(instance->transmitter && + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + manufacture_name, + instance->preset)) { + flipper_format_write_string_cstr(instance->fff_data, "Manufacture", manufacture_name); + res = true; + } + subghz_transmitter_free(instance->transmitter); + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename & lead to a general appearance + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", "BFT"); + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename & lead to a general appearance + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset, + nice_one)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename & lead to a general appearance + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_faac_slh_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + seed, + manufacture_name, + txrx->preset)) { + res = true; + } + + if(res) { + 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] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename & lead to a general appearance + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename & lead to a general appearance + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt) { + SubGhzTxRx* txrx = context; + + bool res = false; + + txrx->transmitter = + subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); + subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0); + + if(txrx->transmitter && subghz_protocol_somfy_telis_create_data( + subghz_transmitter_get_protocol_instance(txrx->transmitter), + txrx->fff_data, + serial, + btn, + cnt, + txrx->preset)) { + res = true; + } + + subghz_transmitter_free(txrx->transmitter); + + return res; +} + +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt) { + furi_assert(instance); + + bool ret = false; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0); + if(instance->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(instance->transmitter), + instance->fff_data, + serial, + btn, + cnt, + instance->preset); + ret = true; + } + return ret; +} + +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency) { + furi_assert(instance); + + bool ret = false; + uint32_t serial = (uint32_t)rand(); + while(!subghz_protocol_secplus_v1_check_fixed(serial)) { + serial = (uint32_t)rand(); + } + if(subghz_txrx_gen_data_protocol( + instance, + name_preset, + frequency, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)serial << 32 | 0xE6000000, + 42)) { + ret = true; + } + return ret; +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h new file mode 100644 index 000000000..99c83a060 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h @@ -0,0 +1,87 @@ +#pragma once +#include "subghz_types.h" +#include "subghz_txrx.h" + +bool subghz_txrx_gen_data_protocol( + void* context, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit); + +bool subghz_txrx_gen_data_protocol_and_te( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + const char* protocol_name, + uint64_t key, + uint32_t bit, + uint32_t te); + +bool subghz_txrx_gen_keelog_protocol( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + bool nice_one); + +bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + uint32_t seed, + const char* manufacture_name); + +bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename + void* context, + const char* preset_name, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint16_t cnt); + +bool subghz_txrx_gen_secplus_v2_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency, + uint32_t serial, + uint8_t btn, + uint32_t cnt); + +bool subghz_txrx_gen_secplus_v1_protocol( + SubGhzTxRx* instance, + const char* name_preset, + uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h new file mode 100644 index 000000000..2d3025554 --- /dev/null +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -0,0 +1,34 @@ + +#pragma once +#include "subghz_types.h" +#include "subghz_txrx_callbacks.h" +#include +#include +#include +#include + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool load_database; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; + + bool debug_pin_state; +}; \ No newline at end of file diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index c249ff282..8bbaae2ce 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -46,14 +46,15 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.event == SubGhzCustomEventSceneExit) { - if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateExit) { - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + SubGhzRxKeyState state = subghz_rx_key_state_get(subghz); + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + + if(state) { subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); scene_manager_previous_scene(subghz->scene_manager); } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index e7e93ad24..4d9553854 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -13,13 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { //set the path to read the file FuriString* temp_str = furi_string_alloc(); do { - if(!flipper_format_rewind(subghz_txtx_get_fff_data(subghz->txrx))) { + FlipperFormat* fff_data = subghz_txtx_get_fff_data(subghz->txrx); + if(!flipper_format_rewind(fff_data)) { FURI_LOG_E(TAG, "Rewind error"); break; } - if(!flipper_format_read_string( - subghz_txtx_get_fff_data(subghz->txrx), "File_name", temp_str)) { + if(!flipper_format_read_string(fff_data, "File_name", temp_str)) { FURI_LOG_E(TAG, "Missing File_name"); break; } @@ -73,13 +73,11 @@ void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; FuriString* file_name = furi_string_alloc(); + float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi); switch(subghz_rx_key_state_get(subghz)) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusIDLE, - "", - subghz_threshold_rssi_get(subghz->threshold_rssi)); + subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi); break; case SubGhzRxKeyStateRAWLoad: path_extract_filename(subghz->file_path, file_name, true); @@ -87,8 +85,7 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, furi_string_get_cstr(file_name), - subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + threshold_rssi); break; case SubGhzRxKeyStateRAWSave: path_extract_filename(subghz->file_path, file_name, true); @@ -96,18 +93,17 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, furi_string_get_cstr(file_name), - subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + threshold_rssi); break; default: subghz_read_raw_set_status( - subghz->subghz_read_raw, - SubGhzReadRAWStatusStart, - "", - subghz_threshold_rssi_get(subghz->threshold_rssi)); - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi); break; } + + if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) { + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + } furi_string_free(file_name); subghz_scene_read_raw_update_statusbar(subghz); @@ -124,13 +120,14 @@ void subghz_scene_read_raw_on_enter(void* context) { bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; + SubGhzProtocolDecoderRAW* decoder_raw = + (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx); if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: subghz_txrx_stop(subghz->txrx); //Stop save file - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); + subghz_protocol_raw_save_to_file_stop(decoder_raw); subghz->state_notifications = SubGhzNotificationStateIDLE; //needed save? if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) || @@ -245,11 +242,9 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReadRAWIDLE: subghz_txrx_stop(subghz->txrx); - size_t spl_count = subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); + size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw); - subghz_protocol_raw_save_to_file_stop( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx)); + subghz_protocol_raw_save_to_file_stop(decoder_raw); FuriString* temp_str = furi_string_alloc(); furi_string_printf( @@ -275,10 +270,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - if(subghz_protocol_raw_save_to_file_init( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), - RAW_FILE_NAME, - &preset)) { + if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); subghz_txrx_rx_start(subghz->txrx); @@ -317,17 +309,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { notification_message(subghz->notifications, &sequence_blink_cyan_10); subghz_read_raw_update_sample_write( - subghz->subghz_read_raw, - subghz_protocol_raw_get_sample_write( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx))); + subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); subghz_read_raw_add_data_rssi( subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); - subghz_protocol_raw_save_to_file_pause( - (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx), - !ret_rssi.is_above); + subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); break; case SubGhzNotificationStateTx: diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 7570d822d..304797eff 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -90,27 +90,26 @@ static void subghz_scene_add_to_history_callback( SubGhzProtocolDecoderBase* decoder_base, void* context) { furi_assert(context); - SubGhz* subghz = context; - + SubGhzHistory* history = subghz->history; FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - uint16_t idx = subghz_history_get_item(subghz->history); + uint16_t idx = subghz_history_get_item(history); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - if(subghz_history_add_to_history(subghz->history, decoder_base, &preset)) { + if(subghz_history_add_to_history(history, decoder_base, &preset)) { furi_string_reset(item_name); furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu(subghz->history, item_name, idx); - subghz_history_get_time_item_menu(subghz->history, item_time, idx); + subghz_history_get_text_item_menu(history, item_name, idx); + subghz_history_get_time_item_menu(history, item_time, idx); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->history, idx)); + subghz_history_get_type_protocol(history, idx)); subghz_scene_receiver_update_statusbar(subghz); } @@ -122,13 +121,14 @@ static void subghz_scene_add_to_history_callback( void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; + SubGhzHistory* history = subghz->history; FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) { subghz_txrx_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); - subghz_history_reset(subghz->history); + subghz_history_reset(history); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart); } @@ -137,16 +137,16 @@ void subghz_scene_receiver_on_enter(void* context) { //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); - for(uint8_t i = 0; i < subghz_history_get_item(subghz->history); i++) { + for(uint8_t i = 0; i < subghz_history_get_item(history); i++) { furi_string_reset(item_name); furi_string_reset(item_time); - subghz_history_get_text_item_menu(subghz->history, item_name, i); - subghz_history_get_time_item_menu(subghz->history, item_time, i); + subghz_history_get_text_item_menu(history, item_name, i); + subghz_history_get_time_item_menu(history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, furi_string_get_cstr(item_name), furi_string_get_cstr(item_time), - subghz_history_get_type_protocol(subghz->history, i)); + subghz_history_get_type_protocol(history, i)); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } furi_string_free(item_name); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 3edde712e..e9f84ed0e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -150,20 +150,20 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) { char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, index); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(setting, index) / 1000000, - (subghz_setting_get_frequency(setting, index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); - - SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), - subghz_setting_get_frequency(setting, index), + frequency, preset.data, preset.data_size); @@ -180,8 +180,9 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { static void subghz_scene_receiver_config_set_preset(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - const char* preset_name = - subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), index); + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + + const char* preset_name = subghz_setting_get_preset_name(setting, index); variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); @@ -190,8 +191,8 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { subghz->txrx, preset_name, preset.frequency, - subghz_setting_get_preset_data(subghz_txrx_get_setting(subghz->txrx), index), - subghz_setting_get_preset_data_size(subghz_txrx_get_setting(subghz->txrx), index)); + subghz_setting_get_preset_data(setting, index), + subghz_setting_get_preset_data_size(setting, index)); } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { @@ -205,6 +206,8 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; uint32_t frequency = subghz_setting_get_default_frequency(setting); + SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + snprintf( text_buf, sizeof(text_buf), @@ -212,7 +215,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) frequency / 1000000, (frequency % 1000000) / 10000); variable_item_set_current_value_text(frequency_item, text_buf); - SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(preset.name), @@ -292,12 +295,13 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; uint8_t value_index; + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); item = variable_item_list_add( subghz->variable_item_list, "Frequency:", - subghz_setting_get_frequency_count(subghz_txrx_get_setting(subghz->txrx)), + subghz_setting_get_frequency_count(setting), subghz_scene_receiver_config_set_frequency, subghz); value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz); @@ -309,23 +313,21 @@ void subghz_scene_receiver_config_on_enter(void* context) { text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), value_index) / 1000000, - (subghz_setting_get_frequency(subghz_txrx_get_setting(subghz->txrx), value_index) % - 1000000) / - 10000); + subghz_setting_get_frequency(setting, value_index) / 1000000, + (subghz_setting_get_frequency(setting, value_index) % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); item = variable_item_list_add( subghz->variable_item_list, "Modulation:", - subghz_setting_get_preset_count(subghz_txrx_get_setting(subghz->txrx)), + subghz_setting_get_preset_count(setting), subghz_scene_receiver_config_set_preset, subghz); value_index = subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text( - item, subghz_setting_get_preset_name(subghz_txrx_get_setting(subghz->txrx), value_index)); + item, subghz_setting_get_preset_name(setting, value_index)); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerSet) { diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index e416d8c2d..d3537689d 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -1,4 +1,5 @@ #include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_potocol_key.h" #define TAG "SubGhzSetSeed" diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 87ef6b0af..076241767 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,4 +1,5 @@ #include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_potocol_key.h" #include #include @@ -366,7 +367,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexBeninca433: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, @@ -381,7 +382,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexBeninca868: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 868350000, @@ -396,7 +397,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAllmatic433: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, @@ -411,7 +412,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAllmatic868: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 868350000, @@ -426,7 +427,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexElmesElectronic: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, @@ -441,7 +442,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexANMotorsAT4: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, @@ -456,7 +457,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAprimatic: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, @@ -471,7 +472,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexGibidi433: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi"); if(!generated_protocol) { furi_string_set( @@ -480,7 +481,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexGSN: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN"); if(!generated_protocol) { furi_string_set( @@ -489,7 +490,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexIronLogic: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic"); if(!generated_protocol) { furi_string_set( @@ -498,7 +499,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSommer_FM_434: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( @@ -507,7 +508,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSommer_FM_868: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( @@ -516,7 +517,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDTMNeo433: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo"); if(!generated_protocol) { furi_string_set( @@ -525,7 +526,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexCAMESpace: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space"); if(!generated_protocol) { furi_string_set( @@ -568,7 +569,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_433_92: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( @@ -577,7 +578,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( @@ -604,7 +605,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexNiceSmilo_433_92: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq( + generated_protocol = subghz_txrx_gen_keelog_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo"); if(!generated_protocol) { furi_string_set( @@ -613,13 +614,16 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexLiftMaster_315_00: - generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000); break; case SubmenuIndexLiftMaster_390_00: - generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000); break; case SubmenuIndexLiftMaster_433_00: - generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 433920000); + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 433920000); break; case SubmenuIndexSecPlus_v2_310_00: generated_protocol = subghz_txrx_gen_secplus_v2_protocol( From e817a4cdba4e9ae278d733941a95a59f9e465f20 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 21:38:25 +0300 Subject: [PATCH 176/216] SubGhz: add function description --- .../main/subghz/helpers/subghz_txrx.h | 216 +++++++++++++++++- .../helpers/subghz_txrx_create_potocol_key.h | 54 +++++ applications/main/subghz/subghz_i.c | 8 +- 3 files changed, 273 insertions(+), 5 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 590fcd4f4..e44b57a13 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -7,20 +7,47 @@ #include #include -typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); - typedef struct SubGhzTxRx SubGhzTxRx; +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + typedef enum { SubGhzTxRxStartTxStateOk, SubGhzTxRxStartTxStateErrorOnlyRx, SubGhzTxRxStartTxStateErrorParserOthers, } SubGhzTxRxStartTxState; +/** + * Allocate SubGhzTxRx + * + * @return SubGhzTxRx* pointer to SubGhzTxRx + */ SubGhzTxRx* subghz_txrx_alloc(); + +/** + * Free SubGhzTxRx + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_free(SubGhzTxRx* instance); + +/** + * Check if the database is loaded + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if the database is loaded + */ bool subghz_txrx_is_load_database(SubGhzTxRx* instance); +/** + * Set preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + */ void subghz_txrx_set_preset( SubGhzTxRx* instance, const char* preset_name, @@ -28,50 +55,235 @@ void subghz_txrx_set_preset( uint8_t* preset_data, size_t preset_data_size); +/** + * Get name of preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset String of preset + * @return const char* Name of preset + */ const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset); + +/** + * Get of preset + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzRadioPreset Preset + */ SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); +/** + * Get string frequency and modulation + * + * @param instance Pointer to a SubGhzTxRx + * @param frequency Pointer to a string frequency + * @param modulation Pointer to a string modulation + */ void subghz_txrx_get_frequency_modulation( SubGhzTxRx* instance, FuriString* frequency, FuriString* modulation, bool long_name); + +/** + * Start TX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + * @param flipper_format Pointer to a FlipperFormat + * @return SubGhzTxRxStartTxState + */ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); + +/** + * Start RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_rx_start(SubGhzTxRx* instance); + +/** + * Stop TX/RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_stop(SubGhzTxRx* instance); + +/** + * Set sleep mode CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_sleep(SubGhzTxRx* instance); +/** + * Update frequency CC1101 in automatic mode (hopper) + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_hopper_update(SubGhzTxRx* instance); + +/** + * Get state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzHopperState + */ SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); + +/** + * Set state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @param state State hopper + */ void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); + +/** + * Unpause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance); + +/** + * Set pause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_hopper_pause(SubGhzTxRx* instance); +/** + * Speaker on + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_speaker_on(SubGhzTxRx* instance); + +/** + * Speaker off + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_speaker_off(SubGhzTxRx* instance); + +/** + * Speaker mute + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_speaker_mute(SubGhzTxRx* instance); + +/** + * Speaker unmute + * + * @param instance Pointer to a SubGhzTxRx + */ void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); + +/** + * Set state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @param state State speaker + */ void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); + +/** + * Get state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSpeakerState + */ SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); + +/** + * load decoder by name protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_protocol Name protocol + * @return bool True if the decoder is loaded + */ bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); + +/** + * Get decoder + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase + */ SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); +/** + * Set callback for save data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for save data + * @param context Context for callback + */ void subghz_txrx_need_save_callback_set( SubGhzTxRx* instance, SubGhzTxRxNeedSaveCallback callback, void* context); + +/** + * Get pointer to a load data key + * + * @param instance Pointer to a SubGhzTxRx + * @return FlipperFormat* + */ FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance); + +/** + * Get pointer to a SugGhzSetting + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSetting* + */ SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); +/** + * Is it possible to save this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to save this protocol + */ bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance); + +/** + * Is it possible to send this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to send this protocol + */ bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type); +/** + * Set filter, what types of decoder to use + * + * @param instance Pointer to a SubGhzTxRx + * @param filter Filter + */ void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); +/** + * Set callback for receive data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for receive data + * @param context Context for callback + */ void subghz_txrx_set_rx_calback( SubGhzTxRx* instance, SubGhzReceiverCallback callback, void* context); + +/** + * Set callback for Raw decoder, end of data transfer + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for Raw decoder, end of data transfer + * @param context Context for callback + */ void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h index 99c83a060..5aa8a31ac 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h @@ -2,6 +2,17 @@ #include "subghz_types.h" #include "subghz_txrx.h" +/** + * Generate data for protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @return bool True if success + */ bool subghz_txrx_gen_data_protocol( void* context, const char* preset_name, @@ -10,6 +21,18 @@ bool subghz_txrx_gen_data_protocol( uint64_t key, uint32_t bit); +/** + * Generate data for protocol and te + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param protocol_name Name of protocol + * @param key Key + * @param bit Bit + * @param te Te + * @return bool True if success + */ bool subghz_txrx_gen_data_protocol_and_te( SubGhzTxRx* instance, const char* preset_name, @@ -19,6 +42,18 @@ bool subghz_txrx_gen_data_protocol_and_te( uint32_t bit, uint32_t te); +/** + * Generate data Keeloq protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @param manufacture_name Name of Keeloq sysmem + * @return bool True if success + */ bool subghz_txrx_gen_keelog_protocol( SubGhzTxRx* instance, const char* preset_name, @@ -73,6 +108,17 @@ bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename uint8_t btn, uint16_t cnt); +/** + * Generate data SecPlus v2 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @param serial Serial number + * @param btn Button + * @param cnt Counter + * @return bool True if success + */ bool subghz_txrx_gen_secplus_v2_protocol( SubGhzTxRx* instance, const char* name_preset, @@ -81,6 +127,14 @@ bool subghz_txrx_gen_secplus_v2_protocol( uint8_t btn, uint32_t cnt); +/** + * Generate data SecPlus v1 protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_preset Name of preset + * @param frequency Frequency in Hz + * @return bool True if success + */ bool subghz_txrx_gen_secplus_v1_protocol( SubGhzTxRx* instance, const char* name_preset, diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index d17c6858f..50a5919ba 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -163,21 +163,23 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { FURI_LOG_E(TAG, "Missing Protocol"); break; } + + FlipperFormat* fff_data = subghz_txtx_get_fff_data(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW subghz->load_type_file = SubGhzLoadTypeFileRaw; - subghz_protocol_raw_gen_fff_data(subghz_txtx_get_fff_data(subghz->txrx), file_path); + subghz_protocol_raw_gen_fff_data(fff_data, file_path); } else { subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx))); + flipper_format_get_raw_stream(fff_data)); } if(subghz_txrx_load_decoder_by_name_protocol( subghz->txrx, furi_string_get_cstr(temp_str))) { SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize( - subghz_txrx_get_decoder(subghz->txrx), subghz_txtx_get_fff_data(subghz->txrx)); + subghz_txrx_get_decoder(subghz->txrx), fff_data); if(status != SubGhzProtocolStatusOk) { load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr; break; From 5b447d0a56c95d10a8902228e445ff7bfc3c4122 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 21:44:53 +0300 Subject: [PATCH 177/216] SubGhz: refactoring --- applications/main/subghz/scenes/subghz_scene_transmitter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index c1bbd2343..8ef61bd53 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -84,7 +84,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(subghz->txrx); if(!subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + scene_manager_next_scene( + subghz->scene_manager, SubGhzSceneShowOnlyRx); //TODO Is this necessary? } subghz_txrx_stop(subghz->txrx); From 85d44c5f6c2cd1e253ba879e19589d3cd1da05a6 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 21:54:56 +0300 Subject: [PATCH 178/216] SubGhz: fix naming part 2 and 3 --- .../main/subghz/helpers/subghz_txrx.c | 22 +++++++++---------- .../main/subghz/helpers/subghz_txrx.h | 18 +++++++-------- .../main/subghz/helpers/subghz_txrx_i.h | 2 +- .../subghz/scenes/subghz_scene_decode_raw.c | 6 ++--- .../main/subghz/scenes/subghz_scene_delete.c | 2 +- .../subghz/scenes/subghz_scene_delete_raw.c | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 10 ++++----- .../subghz/scenes/subghz_scene_receiver.c | 7 +++--- .../scenes/subghz_scene_receiver_info.c | 12 +++++----- .../main/subghz/scenes/subghz_scene_rpc.c | 2 +- .../subghz/scenes/subghz_scene_save_name.c | 4 ++-- .../subghz/scenes/subghz_scene_transmitter.c | 10 ++++----- applications/main/subghz/subghz.c | 4 ++-- applications/main/subghz/subghz_i.c | 8 +++---- 14 files changed, 55 insertions(+), 54 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 38cf549de..fcbebba8f 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -24,7 +24,7 @@ SubGhzTxRx* subghz_txrx_alloc() { instance->fff_data = flipper_format_string_alloc(); instance->environment = subghz_environment_alloc(); - instance->load_database = subghz_environment_load_keystore( + instance->is_database_loaded = subghz_environment_load_keystore( instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); subghz_environment_load_keystore( instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); @@ -60,9 +60,9 @@ void subghz_txrx_free(SubGhzTxRx* instance) { free(instance); } -bool subghz_txrx_is_load_database(SubGhzTxRx* instance) { +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { furi_assert(instance); - return instance->load_database; + return instance->is_database_loaded; } void subghz_txrx_set_preset( @@ -79,7 +79,7 @@ void subghz_txrx_set_preset( preset->data_size = preset_data_size; } -const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset) { +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { UNUSED(instance); const char* preset_name = NULL; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { @@ -103,7 +103,7 @@ SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { return *instance->preset; } -void subghz_txrx_get_frequency_modulation( +void subghz_txrx_get_frequency_and_modulation( SubGhzTxRx* instance, FuriString* frequency, FuriString* modulation, @@ -282,7 +282,7 @@ void subghz_txrx_rx_start(SubGhzTxRx* instance) { subghz_txrx_rx(instance, instance->preset->frequency); } -void subghz_txrx_need_save_callback_set( +void subghz_txrx_set_need_save_callback( SubGhzTxRx* instance, SubGhzTxRxNeedSaveCallback callback, void* context) { @@ -311,7 +311,7 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { // notification_message(notifications, &sequence_reset_red); } -FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance) { +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { furi_assert(instance); return instance->fff_data; } @@ -398,7 +398,7 @@ void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) instance->hopper_state = state; } -void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance) { +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { furi_assert(instance); if(instance->hopper_state == SubGhzHopperStatePause) { instance->hopper_state = SubGhzHopperStateRunning; @@ -501,14 +501,14 @@ SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { return instance->decoder_result; } -bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance) { +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { furi_assert(instance); return ( (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == SubGhzProtocolFlag_Save); } -bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type) { +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { furi_assert(instance); const SubGhzProtocol* protocol = instance->decoder_result->protocol; if(check_type) { @@ -533,7 +533,7 @@ void subghz_txrx_set_rx_calback( subghz_receiver_set_rx_callback(instance->receiver, callback, context); } -void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( +void subghz_txrx_set_raw_file_encoder_worker_callback_end( SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context) { diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index e44b57a13..f2bf6d9a1 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -37,7 +37,7 @@ void subghz_txrx_free(SubGhzTxRx* instance); * @param instance Pointer to a SubGhzTxRx * @return bool True if the database is loaded */ -bool subghz_txrx_is_load_database(SubGhzTxRx* instance); +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance); /** * Set preset @@ -62,7 +62,7 @@ void subghz_txrx_set_preset( * @param preset String of preset * @return const char* Name of preset */ -const char* subghz_txrx_get_name_preset(SubGhzTxRx* instance, const char* preset); +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset); /** * Get of preset @@ -79,7 +79,7 @@ SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); * @param frequency Pointer to a string frequency * @param modulation Pointer to a string modulation */ -void subghz_txrx_get_frequency_modulation( +void subghz_txrx_get_frequency_and_modulation( SubGhzTxRx* instance, FuriString* frequency, FuriString* modulation, @@ -143,7 +143,7 @@ void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) * * @param instance Pointer to a SubGhzTxRx */ -void subghz_txrx_hopper_remove_pause(SubGhzTxRx* instance); +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance); /** * Set pause hopper @@ -220,7 +220,7 @@ SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); * @param callback Callback for save data * @param context Context for callback */ -void subghz_txrx_need_save_callback_set( +void subghz_txrx_set_need_save_callback( SubGhzTxRx* instance, SubGhzTxRxNeedSaveCallback callback, void* context); @@ -231,7 +231,7 @@ void subghz_txrx_need_save_callback_set( * @param instance Pointer to a SubGhzTxRx * @return FlipperFormat* */ -FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* instance); +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance); /** * Get pointer to a SugGhzSetting @@ -247,7 +247,7 @@ SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); * @param instance Pointer to a SubGhzTxRx * @return bool True if it is possible to save this protocol */ -bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance); +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance); /** * Is it possible to send this protocol @@ -255,7 +255,7 @@ bool subghz_txrx_protocol_is_preserved(SubGhzTxRx* instance); * @param instance Pointer to a SubGhzTxRx * @return bool True if it is possible to send this protocol */ -bool subghz_txrx_protocol_is_send(SubGhzTxRx* instance, bool check_type); +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type); /** * Set filter, what types of decoder to use @@ -284,7 +284,7 @@ void subghz_txrx_set_rx_calback( * @param callback Callback for Raw decoder, end of data transfer * @param context Context for callback */ -void subghz_txrx_set_raw_file_encoder_worker_set_callback_end( +void subghz_txrx_set_raw_file_encoder_worker_callback_end( SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context); diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h index 2d3025554..e5c1445ea 100644 --- a/applications/main/subghz/helpers/subghz_txrx_i.h +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -21,7 +21,7 @@ struct SubGhzTxRx { uint8_t hopper_timeout; uint8_t hopper_idx_frequency; - bool load_database; + bool is_database_loaded; SubGhzHopperState hopper_state; SubGhzTxRxState txrx_state; diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index f008db380..5ad12b509 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -29,7 +29,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, @@ -88,13 +88,13 @@ bool subghz_scene_decode_raw_start(SubGhz* subghz) { FuriString* file_name = furi_string_alloc(); bool success = false; do { - if(!flipper_format_rewind(subghz_txtx_get_fff_data(subghz->txrx))) { + if(!flipper_format_rewind(subghz_txrx_get_fff_data(subghz->txrx))) { FURI_LOG_E(TAG, "Rewind error"); break; } if(!flipper_format_read_string( - subghz_txtx_get_fff_data(subghz->txrx), "File_name", file_name)) { + subghz_txrx_get_fff_data(subghz->txrx), "File_name", file_name)) { FURI_LOG_E(TAG, "Missing File_name"); break; } diff --git a/applications/main/subghz/scenes/subghz_scene_delete.c b/applications/main/subghz/scenes/subghz_scene_delete.c index 095cdf899..3fc4be069 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete.c +++ b/applications/main/subghz/scenes/subghz_scene_delete.c @@ -15,7 +15,7 @@ void subghz_scene_delete_on_enter(void* context) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, diff --git a/applications/main/subghz/scenes/subghz_scene_delete_raw.c b/applications/main/subghz/scenes/subghz_scene_delete_raw.c index bc8a4d6ef..ada0f4c5c 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_raw.c @@ -30,7 +30,7 @@ void subghz_scene_delete_raw_on_enter(void* context) { widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 35, diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 4d9553854..a858ca355 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -13,7 +13,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { //set the path to read the file FuriString* temp_str = furi_string_alloc(); do { - FlipperFormat* fff_data = subghz_txtx_get_fff_data(subghz->txrx); + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); if(!flipper_format_rewind(fff_data)) { FURI_LOG_E(TAG, "Rewind error"); break; @@ -41,7 +41,7 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { FuriString* modulation_str = furi_string_alloc(); #ifdef SUBGHZ_EXT_PRESET_NAME - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, true); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, true); //TODO if need subghz_txrx_get_preset //furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); #else @@ -206,7 +206,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz->state_notifications = SubGhzNotificationStateIDLE; subghz_txrx_stop(subghz->txrx); - if(!subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( subghz->subghz_read_raw, @@ -219,7 +219,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { DOLPHIN_DEED(DolphinDeedSubGhzSend); } // set callback end tx - subghz_txrx_set_raw_file_encoder_worker_set_callback_end( + subghz_txrx_set_raw_file_encoder_worker_callback_end( subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz); subghz->state_notifications = SubGhzNotificationStateTx; } @@ -250,7 +250,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz_txtx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); furi_string_free(temp_str); if(spl_count > 0) { diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 304797eff..8abb6aff3 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -46,12 +46,12 @@ static void subghz_scene_receiver_update_statusbar(void* context) { #ifdef SUBGHZ_EXT_PRESET_NAME if(subghz_history_get_last_index(subghz->history) > 0) { - subghz_txrx_get_frequency_modulation( + subghz_txrx_get_frequency_and_modulation( subghz->txrx, frequency_str, modulation_str, false); } else { FuriString* temp_str = furi_string_alloc(); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, temp_str, true); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, temp_str, true); furi_string_printf( modulation_str, "%s Mod: %s", @@ -60,7 +60,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { furi_string_free(temp_str); } #else - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation( + subghz->txrx, frequency_str, modulation_str, false); #endif subghz_view_receiver_add_data_statusbar( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index c92573e85..5a4dbf5d4 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -52,7 +52,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_txrx_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, @@ -78,7 +78,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { furi_string_free(modulation_str); furi_string_free(text); - if(subghz_txrx_protocol_is_preserved(subghz->txrx)) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { widget_add_button_element( subghz->widget, GuiButtonTypeRight, @@ -87,7 +87,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { subghz); } // Removed static check - if(subghz_txrx_protocol_is_send(subghz->txrx, false)) { + if(subghz_txrx_protocol_is_transmittable(subghz->txrx, false)) { widget_add_button_element( subghz->widget, GuiButtonTypeCenter, @@ -127,7 +127,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz, subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) { subghz_txrx_rx_start(subghz->txrx); - subghz_txrx_hopper_remove_pause(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } else { subghz->state_notifications = SubGhzNotificationStateTx; @@ -144,7 +144,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(!subghz->in_decoder_scene) { subghz_txrx_rx_start(subghz->txrx); - subghz_txrx_hopper_remove_pause(subghz->txrx); + subghz_txrx_hopper_unpause(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; } return true; @@ -158,7 +158,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) return false; } - if(subghz_txrx_protocol_is_preserved(subghz->txrx)) { + if(subghz_txrx_protocol_is_serializable(subghz->txrx)) { subghz_file_name_clear(subghz); if(subghz->in_decoder_scene) { diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 59497c493..ef718c4e1 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -44,7 +44,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; if((state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx)); + result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); state = SubGhzRpcStateTx; if(result) subghz_blink_start(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index c05230d97..b0c3a1b12 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -147,7 +147,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( subghz, - subghz_txtx_get_fff_data(subghz->txrx), + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, @@ -164,7 +164,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( - subghz_txtx_get_fff_data(subghz->txrx), + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 8ef61bd53..5ac1b0a27 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -23,17 +23,17 @@ bool subghz_scene_transmitter_update_data_show(void* context) { FuriString* modulation_str = furi_string_alloc(); if(subghz_protocol_decoder_base_deserialize( - decoder, subghz_txtx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { + decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) { subghz_protocol_decoder_base_get_string(decoder, key_str); - subghz_txrx_get_frequency_modulation( + subghz_txrx_get_frequency_and_modulation( subghz->txrx, frequency_str, modulation_str, false); subghz_view_transmitter_add_data_to_show( subghz->subghz_transmitter, furi_string_get_cstr(key_str), furi_string_get_cstr(frequency_str), furi_string_get_cstr(modulation_str), - subghz_txrx_protocol_is_send(subghz->txrx, false)); + subghz_txrx_protocol_is_transmittable(subghz->txrx, false)); ret = true; } furi_string_free(frequency_str); @@ -67,7 +67,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(event.event == SubGhzCustomEventViewTransmitterSendStart) { subghz->state_notifications = SubGhzNotificationStateIDLE; - if(subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { + if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); DOLPHIN_DEED(DolphinDeedSubGhzSend); @@ -83,7 +83,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { // Calling restore! subghz_txrx_stop(subghz->txrx); - if(!subghz_tx_start(subghz, subghz_txtx_get_fff_data(subghz->txrx))) { + if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { scene_manager_next_scene( subghz->scene_manager, SubGhzSceneShowOnlyRx); //TODO Is this necessary? } diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 4bf6e7aaf..f9413bbfb 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -265,7 +265,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->filter = SubGhzProtocolFlag_Decodable; subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); - subghz_txrx_need_save_callback_set(subghz->txrx, subghz_save_to_file, subghz); + subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz); //Init Error_str subghz->error_str = furi_string_alloc(); @@ -446,7 +446,7 @@ int32_t subghz_app(void* p) { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); - if(subghz_txrx_is_load_database(subghz->txrx)) { + if(subghz_txrx_is_database_loaded(subghz->txrx)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); } else { scene_manager_set_scene_state( diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 50a5919ba..243a1a123 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -79,7 +79,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); Stream* fff_data_stream = - flipper_format_get_raw_stream(subghz_txtx_get_fff_data(subghz->txrx)); + flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx)); SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr; FuriString* temp_str = furi_string_alloc(); @@ -129,7 +129,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { } furi_string_set_str( - temp_str, subghz_txrx_get_name_preset(subghz->txrx, furi_string_get_cstr(temp_str))); + temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str))); if(temp_str == NULL) { break; } @@ -164,7 +164,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - FlipperFormat* fff_data = subghz_txtx_get_fff_data(subghz->txrx); + FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW subghz->load_type_file = SubGhzLoadTypeFileRaw; @@ -276,7 +276,7 @@ void subghz_save_to_file(void* context) { if(subghz_path_is_file(subghz->file_path)) { subghz_save_protocol_to_file( subghz, - subghz_txtx_get_fff_data(subghz->txrx), + subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(subghz->file_path)); } } From 0019baaa00993f1e1da6bdc102915557416ab7ff Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 21:58:36 +0300 Subject: [PATCH 179/216] SubGhz: simplify includes --- applications/main/subghz/helpers/subghz_txrx.c | 1 - applications/main/subghz/helpers/subghz_txrx.h | 1 - applications/main/subghz/helpers/subghz_txrx_callbacks.h | 2 -- applications/main/subghz/helpers/subghz_txrx_i.h | 7 +------ 4 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 applications/main/subghz/helpers/subghz_txrx_callbacks.h diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index fcbebba8f..a96004046 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,5 +1,4 @@ #include "subghz_txrx_i.h" -#include "subghz_txrx.h" #include #define TAG "SubGhz" diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index f2bf6d9a1..edd7fa81d 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -1,6 +1,5 @@ #pragma once #include "subghz_types.h" -#include "subghz_txrx_callbacks.h" #include #include #include diff --git a/applications/main/subghz/helpers/subghz_txrx_callbacks.h b/applications/main/subghz/helpers/subghz_txrx_callbacks.h deleted file mode 100644 index 5bee720e9..000000000 --- a/applications/main/subghz/helpers/subghz_txrx_callbacks.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h index e5c1445ea..680d27158 100644 --- a/applications/main/subghz/helpers/subghz_txrx_i.h +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -1,11 +1,6 @@ #pragma once -#include "subghz_types.h" -#include "subghz_txrx_callbacks.h" -#include -#include -#include -#include +#include "subghz_txrx.h" struct SubGhzTxRx { SubGhzWorker* worker; From a3cf592f298c93ffb3af71a10fd1f62466223b33 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 9 May 2023 22:16:52 +0300 Subject: [PATCH 180/216] Minor fixes --- .../main/subghz/helpers/subghz_txrx.c | 7 +++++- .../main/subghz/helpers/subghz_txrx.h | 2 ++ applications/main/subghz/subghz_i.c | 24 +++++++++---------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index a96004046..c1f519ba0 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -80,7 +80,7 @@ void subghz_txrx_set_preset( const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { UNUSED(instance); - const char* preset_name = NULL; + const char* preset_name = ""; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { preset_name = "AM270"; } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { @@ -198,6 +198,7 @@ static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { subghz_txrx_speaker_on(instance); instance->txrx_state = SubGhzTxRxStateTx; } + return ret; } @@ -245,11 +246,13 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* } else { ret = SubGhzTxRxStartTxStateErrorParserOthers; } + } else { FURI_LOG_E( TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); ret = SubGhzTxRxStartTxStateErrorParserOthers; } + if(ret == SubGhzTxRxStartTxStateOk) { //Start TX furi_hal_subghz_start_async_tx( @@ -258,6 +261,8 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* } else { ret = SubGhzTxRxStartTxStateErrorParserOthers; } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; } if(ret != SubGhzTxRxStartTxStateOk) { subghz_transmitter_free(instance->transmitter); diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index edd7fa81d..fd7c024b8 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -1,5 +1,7 @@ #pragma once + #include "subghz_types.h" + #include #include #include diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 243a1a123..205c7ca02 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -130,7 +130,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { furi_string_set_str( temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str))); - if(temp_str == NULL) { + if(!strcmp(furi_string_get_cstr(temp_str), "")) { break; } @@ -270,17 +270,6 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { return res; } -void subghz_save_to_file(void* context) { - furi_assert(context); - SubGhz* subghz = context; - if(subghz_path_is_file(subghz->file_path)) { - subghz_save_protocol_to_file( - subghz, - subghz_txrx_get_fff_data(subghz->txrx), - furi_string_get_cstr(subghz->file_path)); - } -} - bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, @@ -321,6 +310,17 @@ bool subghz_save_protocol_to_file( return saved; } +void subghz_save_to_file(void* context) { + furi_assert(context); + SubGhz* subghz = context; + if(subghz_path_is_file(subghz->file_path)) { + subghz_save_protocol_to_file( + subghz, + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(subghz->file_path)); + } +} + bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); From 6f109903867ee0f208e1113febdfa96fab227cea Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Wed, 10 May 2023 13:21:42 +0300 Subject: [PATCH 181/216] SubGhz: fix syntax & minor fixes --- .../subghz/scenes/subghz_scene_need_saving.c | 2 +- .../main/subghz/scenes/subghz_scene_read_raw.c | 5 +---- .../main/subghz/scenes/subghz_scene_receiver.c | 1 - .../scenes/subghz_scene_receiver_config.c | 8 ++++---- .../subghz/scenes/subghz_scene_receiver_info.c | 6 +++--- .../main/subghz/scenes/subghz_scene_saved.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_i.c | 17 +++++++---------- 9 files changed, 19 insertions(+), 26 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_need_saving.c b/applications/main/subghz/scenes/subghz_scene_need_saving.c index 8bbaae2ce..8259b6e82 100644 --- a/applications/main/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/main/subghz/scenes/subghz_scene_need_saving.c @@ -49,7 +49,7 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhzRxKeyState state = subghz_rx_key_state_get(subghz); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - if(state) { + if(state == SubGhzRxKeyStateExit) { subghz_txrx_set_preset( subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0); scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index a858ca355..4b8303ddd 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -125,6 +125,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubGhzCustomEventViewReadRAWBack: + subghz_txrx_stop(subghz->txrx); //Stop save file subghz_protocol_raw_save_to_file_stop(decoder_raw); @@ -204,8 +205,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; - - subghz_txrx_stop(subghz->txrx); if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack); subghz_read_raw_set_status( @@ -273,7 +272,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { DOLPHIN_DEED(DolphinDeedSubGhzRawRec); subghz_txrx_rx_start(subghz->txrx); - subghz->state_notifications = SubGhzNotificationStateRx; subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { @@ -316,7 +314,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_add_data_rssi( subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); - break; case SubGhzNotificationStateTx: notification_message(subghz->notifications, &sequence_blink_magenta_10); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 8abb6aff3..9987449cd 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -184,7 +184,6 @@ void subghz_scene_receiver_on_enter(void* context) { } subghz->state_notifications = SubGhzNotificationStateRx; - subghz_txrx_stop(subghz->txrx); subghz_txrx_rx_start(subghz->txrx); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index e9f84ed0e..29d55c03a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -92,9 +92,9 @@ const char* const magellan_text[MAGELLAN_COUNT] = { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); SubGhz* subghz = context; - uint8_t index = 0; SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); + uint8_t index = 0; for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) { if(value == subghz_setting_get_frequency(setting, i)) { index = i; @@ -186,7 +186,6 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { variable_item_set_current_value_text(item, preset_name); //subghz->last_settings->preset = index; SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); - subghz_txrx_set_preset( subghz->txrx, preset_name, @@ -309,12 +308,13 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); variable_item_set_current_value_index(item, value_index); char text_buf[10] = {0}; + uint32_t frequency = subghz_setting_get_frequency(setting, value_index); snprintf( text_buf, sizeof(text_buf), "%lu.%02lu", - subghz_setting_get_frequency(setting, value_index) / 1000000, - (subghz_setting_get_frequency(setting, value_index) % 1000000) / 10000); + frequency / 1000000, + (frequency % 1000000) / 10000); variable_item_set_current_value_text(item, text_buf); item = variable_item_list_add( diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 5a4dbf5d4..c04f39cb8 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -52,7 +52,8 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { FuriString* modulation_str = furi_string_alloc(); FuriString* text = furi_string_alloc(); - subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation( + subghz->txrx, frequency_str, modulation_str, false); widget_add_string_element( subghz->widget, 78, @@ -120,7 +121,6 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - //CC1101 Stop RX -> Start TX subghz_txrx_hopper_pause(subghz->txrx); if(!subghz_tx_start( @@ -140,7 +140,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); - subghz_txrx_stop(subghz->txrx); + subghz_txrx_stop(subghz->txrx); //TODO this is probably a redundant call if(!subghz->in_decoder_scene) { subghz_txrx_rx_start(subghz->txrx); diff --git a/applications/main/subghz/scenes/subghz_scene_saved.c b/applications/main/subghz/scenes/subghz_scene_saved.c index eca5ab801..8b198e339 100644 --- a/applications/main/subghz/scenes/subghz_scene_saved.c +++ b/applications/main/subghz/scenes/subghz_scene_saved.c @@ -4,7 +4,7 @@ void subghz_scene_saved_on_enter(void* context) { SubGhz* subghz = context; if(subghz_load_protocol_from_file(subghz)) { - if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 5ac1b0a27..c3ae04a8f 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -81,7 +81,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! - subghz_txrx_stop(subghz->txrx); + subghz_txrx_stop(subghz->txrx); //TODO this is probably a redundant call if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { scene_manager_next_scene( diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index f9413bbfb..975ec540a 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -428,7 +428,7 @@ int32_t subghz_app(void* p) { if(subghz_key_load(subghz, p, true)) { furi_string_set(subghz->file_path, (const char*)p); - if((subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw)) { + if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { //Load Raw TX subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 205c7ca02..70812ed11 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -133,30 +133,27 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { if(!strcmp(furi_string_get_cstr(temp_str), "")) { break; } + SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx); if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { //Todo add Custom_preset_module //delete preset if it already exists - subghz_setting_delete_custom_preset( - subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); + subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str)); //load custom preset from file if(!subghz_setting_load_custom_preset( - subghz_txrx_get_setting(subghz->txrx), - furi_string_get_cstr(temp_str), - fff_data_file)) { + setting, furi_string_get_cstr(temp_str), fff_data_file)) { FURI_LOG_E(TAG, "Missing Custom preset"); break; } } - size_t preset_index = subghz_setting_get_inx_preset_by_name( - subghz_txrx_get_setting(subghz->txrx), furi_string_get_cstr(temp_str)); + size_t preset_index = + subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); subghz_txrx_set_preset( subghz->txrx, furi_string_get_cstr(temp_str), temp_data32, - subghz_setting_get_preset_data(subghz_txrx_get_setting(subghz->txrx), preset_index), - subghz_setting_get_preset_data_size( - subghz_txrx_get_setting(subghz->txrx), preset_index)); + subghz_setting_get_preset_data(setting, preset_index), + subghz_setting_get_preset_data_size(setting, preset_index)); //Load protocol if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { From 33ff8e4506b4e6e269f7617436fa60992c9e344a Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 12:13:38 +0100 Subject: [PATCH 182/216] Start storage service first to load xtreme early --- applications/services/desktop/desktop.c | 4 --- applications/services/dolphin/dolphin.c | 2 +- applications/services/gui/gui.c | 6 ++++ .../services/rgb_backlight/application.fam | 1 + applications/services/storage/application.fam | 2 +- applications/services/storage/storage.c | 4 --- applications/system/updater/application.fam | 2 +- firmware/targets/f7/api_symbols.csv | 1 - furi/flipper.c | 31 ++++++++++++------- lib/xtreme/assets.c | 7 ----- lib/xtreme/private.h | 2 +- lib/xtreme/settings.c | 12 ------- lib/xtreme/xtreme.h | 2 -- 13 files changed, 31 insertions(+), 45 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 127afdcdb..10c8944bd 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -15,7 +15,6 @@ #include "desktop/views/desktop_view_pin_timeout.h" #include "desktop_i.h" #include "helpers/pin_lock.h" -#include #define TAG "Desktop" @@ -347,9 +346,6 @@ int32_t desktop_srv(void* p) { furi_hal_rtc_reset_flag(FuriHalRtcFlagResetPin); } - XTREME_SETTINGS_LOAD(); - XTREME_ASSETS_LOAD(); - Desktop* desktop = desktop_alloc(); bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 145224542..5e5ff07d3 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -80,7 +80,7 @@ Dolphin* dolphin_alloc() { dolphin->state = dolphin_state_alloc(); dolphin->event_queue = furi_message_queue_alloc(8, sizeof(DolphinEvent)); dolphin->pubsub = furi_pubsub_alloc(); - int32_t butthurt = XTREME_SETTINGS_WAIT()->butthurt_timer; + int32_t butthurt = XTREME_SETTINGS()->butthurt_timer; dolphin->butthurt_timer = xTimerCreate( NULL, (butthurt > 0) ? (butthurt * 1000) : -1, diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 8f0deaa6f..dd3b4114e 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -1,6 +1,8 @@ #include #include "gui_i.h" #include +#include +#include #define TAG "GuiSrv" @@ -589,6 +591,10 @@ Gui* gui_alloc() { furi_check(gui->input_events); furi_pubsub_subscribe(gui->input_events, gui_input_events_callback, gui); + Storage* storage = furi_record_open(RECORD_STORAGE); + gui_add_view_port(gui, storage->sd_gui.view_port, GuiLayerStatusBarLeft); + furi_record_close(RECORD_STORAGE); + return gui; } diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam index 70fc0dc9a..20b7d0fed 100644 --- a/applications/services/rgb_backlight/application.fam +++ b/applications/services/rgb_backlight/application.fam @@ -3,6 +3,7 @@ App( name="RGB Backlight", apptype=FlipperAppType.SERVICE, entry_point="rgb_backlight_srv", + order=10, sdk_headers=[ "rgb_backlight.h", ], diff --git a/applications/services/storage/application.fam b/applications/services/storage/application.fam index 7b106e00f..89fa48e63 100644 --- a/applications/services/storage/application.fam +++ b/applications/services/storage/application.fam @@ -7,7 +7,7 @@ App( requires=["storage_settings"], provides=["storage_start"], stack_size=3 * 1024, - order=44, + order=0, sdk_headers=["storage.h"], ) diff --git a/applications/services/storage/storage.c b/applications/services/storage/storage.c index 1816bf921..f746196c2 100644 --- a/applications/services/storage/storage.c +++ b/applications/services/storage/storage.c @@ -54,10 +54,6 @@ Storage* storage_app_alloc() { view_port_draw_callback_set(app->sd_gui.view_port, storage_app_sd_icon_draw_callback, app); view_port_enabled_set(app->sd_gui.view_port, false); - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, app->sd_gui.view_port, GuiLayerStatusBarLeft); - furi_record_close(RECORD_GUI); - return app; } diff --git a/applications/system/updater/application.fam b/applications/system/updater/application.fam index 4d62c1d48..bdbb69fda 100644 --- a/applications/system/updater/application.fam +++ b/applications/system/updater/application.fam @@ -12,7 +12,7 @@ App( conflicts=["desktop"], entry_point="updater_srv", stack_size=2 * 1024, - order=130, + order=120, ) App( diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ba82545e3..b1dfb9afe 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -325,7 +325,6 @@ Function,-,SystemInit,void, Function,+,XTREME_ASSETS,XtremeAssets*, Function,+,XTREME_SETTINGS,XtremeSettings*, Function,+,XTREME_SETTINGS_SAVE,void, -Function,+,XTREME_SETTINGS_WAIT,XtremeSettings*, Function,-,_Exit,void,int Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" diff --git a/furi/flipper.c b/furi/flipper.c index 8806ce27f..1b13d8bf1 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -4,6 +4,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -27,23 +28,31 @@ static void flipper_print_version(const char* target, const Version* version) { } } +void flipper_start_service(const FlipperApplication* service) { + FURI_LOG_D(TAG, "Starting service %s", service->name); + + FuriThread* thread = + furi_thread_alloc_ex(service->name, service->stack_size, service->app, NULL); + furi_thread_mark_as_service(thread); + furi_thread_set_appid(thread, service->appid); + + furi_thread_start(thread); + } + void flipper_init() { flipper_print_version("Firmware", furi_hal_version_get_firmware_version()); 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_D(TAG, "Starting service %s", FLIPPER_SERVICES[i].name); + // Start storage service first, thanks OFW :/ + flipper_start_service(&FLIPPER_SERVICES[0]); - FuriThread* thread = furi_thread_alloc_ex( - FLIPPER_SERVICES[i].name, - FLIPPER_SERVICES[i].stack_size, - FLIPPER_SERVICES[i].app, - NULL); - furi_thread_mark_as_service(thread); - furi_thread_set_appid(thread, FLIPPER_SERVICES[i].appid); + XTREME_SETTINGS_LOAD(); + XTREME_ASSETS_LOAD(); - furi_thread_start(thread); + // Everything else + for(size_t i = 1; i < FLIPPER_SERVICES_COUNT; i++) { + flipper_start_service(&FLIPPER_SERVICES[i]); } FURI_LOG_I(TAG, "Startup complete"); @@ -65,4 +74,4 @@ void vApplicationGetTimerTaskMemory( *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH); *stack_size = configTIMER_TASK_STACK_DEPTH; -} \ No newline at end of file +} diff --git a/lib/xtreme/assets.c b/lib/xtreme/assets.c index cc1a6fe0d..828369ad1 100644 --- a/lib/xtreme/assets.c +++ b/lib/xtreme/assets.c @@ -148,13 +148,6 @@ void XTREME_ASSETS_LOAD() { xtreme_assets.is_nsfw = strncmp(xtreme_settings->asset_pack, "NSFW", strlen("NSFW")) == 0; Storage* storage = furi_record_open(RECORD_STORAGE); - int32_t timeout = 5000; - while(timeout > 0) { - if(storage_sd_status(storage) == FSE_OK) break; - furi_delay_ms(250); - timeout -= 250; - } - FileInfo info; FuriString* path = furi_string_alloc(); furi_string_printf(path, XTREME_ASSETS_PATH "/%s", xtreme_settings->asset_pack); diff --git a/lib/xtreme/private.h b/lib/xtreme/private.h index 8b220f586..d1644c3e3 100644 --- a/lib/xtreme/private.h +++ b/lib/xtreme/private.h @@ -1,4 +1,4 @@ #pragma once -void XTREME_ASSETS_LOAD(); void XTREME_SETTINGS_LOAD(); +void XTREME_ASSETS_LOAD(); diff --git a/lib/xtreme/settings.c b/lib/xtreme/settings.c index 88aa55b99..f840f990d 100644 --- a/lib/xtreme/settings.c +++ b/lib/xtreme/settings.c @@ -6,7 +6,6 @@ #define TAG "XtremeSettings" XtremeSettings xtreme_settings = { - .loaded = false, .asset_pack = "", .anim_speed = 100, // 100% .cycle_anims = 0, // Meta.txt @@ -89,8 +88,6 @@ void XTREME_SETTINGS_LOAD() { } flipper_format_free(file); furi_record_close(RECORD_STORAGE); - - xtreme_settings.loaded = true; } void XTREME_SETTINGS_SAVE() { @@ -131,12 +128,3 @@ void XTREME_SETTINGS_SAVE() { XtremeSettings* XTREME_SETTINGS() { return &xtreme_settings; } - -XtremeSettings* XTREME_SETTINGS_WAIT() { - if(furi_hal_is_normal_boot()) { - while(!xtreme_settings.loaded) { - furi_delay_ms(50); - } - } - return &xtreme_settings; -} diff --git a/lib/xtreme/xtreme.h b/lib/xtreme/xtreme.h index e4baeeeba..b84ba9691 100644 --- a/lib/xtreme/xtreme.h +++ b/lib/xtreme/xtreme.h @@ -13,7 +13,6 @@ extern "C" { #define XTREME_ASSETS_PACK_NAME_LEN 32 typedef struct { - bool loaded; char asset_pack[XTREME_ASSETS_PACK_NAME_LEN]; uint32_t anim_speed; int32_t cycle_anims; @@ -41,7 +40,6 @@ typedef struct { void XTREME_SETTINGS_SAVE(); XtremeSettings* XTREME_SETTINGS(); -XtremeSettings* XTREME_SETTINGS_WAIT(); typedef struct { bool is_nsfw; From 640637ce6094bf1f23ebb77c0f116f6e542a4f52 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 12:19:01 +0100 Subject: [PATCH 183/216] New namespoof implementation --- .../scenes/xtreme_app_scene_misc_rename.c | 2 +- applications/main/xtreme_app/xtreme_app.c | 21 +-- applications/main/xtreme_app/xtreme_app.h | 4 +- applications/services/application.fam | 1 - .../services/namechangersrv/application.fam | 7 - .../services/namechangersrv/namechangersrv.c | 163 ------------------ .../services/namechangersrv/namechangersrv.h | 10 -- firmware/targets/f7/api_symbols.csv | 2 +- .../targets/f7/furi_hal/furi_hal_version.c | 23 +-- .../furi_hal_include/furi_hal_version.h | 2 +- furi/flipper.c | 7 +- lib/xtreme/namespoof.c | 26 +++ lib/xtreme/namespoof.h | 5 + lib/xtreme/private.h | 1 + 14 files changed, 50 insertions(+), 224 deletions(-) delete mode 100644 applications/services/namechangersrv/application.fam delete mode 100644 applications/services/namechangersrv/namechangersrv.c delete mode 100644 applications/services/namechangersrv/namechangersrv.h create mode 100644 lib/xtreme/namespoof.c create mode 100644 lib/xtreme/namespoof.h diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_rename.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_rename.c index 47a0fb607..dd01a60ca 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_rename.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc_rename.c @@ -42,7 +42,7 @@ void xtreme_app_scene_misc_rename_on_enter(void* context) { xtreme_app_scene_misc_rename_text_input_callback, app, app->device_name, - NAMECHANGER_TEXT_STORE_SIZE, + FURI_HAL_VERSION_ARRAY_NAME_LENGTH, true); view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewTextInput); diff --git a/applications/main/xtreme_app/xtreme_app.c b/applications/main/xtreme_app/xtreme_app.c index 57706233e..e86db4fc5 100644 --- a/applications/main/xtreme_app/xtreme_app.c +++ b/applications/main/xtreme_app/xtreme_app.c @@ -69,28 +69,15 @@ bool xtreme_app_apply(XtremeApp* app) { if(app->save_name) { if(strcmp(app->device_name, "") == 0) { - storage_simply_remove(storage, NAMECHANGER_PATH); + storage_simply_remove(storage, NAMESPOOF_PATH); } else { FlipperFormat* file = flipper_format_file_alloc(storage); do { - if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) break; - - if(!flipper_format_write_header_cstr(file, NAMECHANGER_HEADER, 1)) break; - - if(!flipper_format_write_comment_cstr( - file, "Changing the value below will change your FlipperZero device name.")) + if(!flipper_format_file_open_always(file, NAMESPOOF_PATH)) break; + if(!flipper_format_write_header_cstr(file, NAMESPOOF_HEADER, NAMESPOOF_VERSION)) break; - if(!flipper_format_write_comment_cstr( - file, - "Note: This is limited to 8 characters using the following: a-z, A-Z, 0-9, and _")) - break; - if(!flipper_format_write_comment_cstr( - file, "It cannot contain any other characters.")) - break; - if(!flipper_format_write_string_cstr(file, "Name", app->device_name)) break; - } while(0); flipper_format_free(file); @@ -262,7 +249,7 @@ XtremeApp* xtreme_app_alloc() { furi_hal_subghz_get_extend_settings(&app->subghz_extend, &app->subghz_bypass); - strlcpy(app->device_name, furi_hal_version_get_name_ptr(), NAMECHANGER_TEXT_STORE_SIZE); + strlcpy(app->device_name, furi_hal_version_get_name_ptr(), FURI_HAL_VERSION_ARRAY_NAME_LENGTH); Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); diff --git a/applications/main/xtreme_app/xtreme_app.h b/applications/main/xtreme_app/xtreme_app.h index 15cd71ce9..f7d79249d 100644 --- a/applications/main/xtreme_app/xtreme_app.h +++ b/applications/main/xtreme_app/xtreme_app.h @@ -12,7 +12,6 @@ #include #include #include -#include #include "scenes/xtreme_app_scene.h" #include "dolphin/helpers/dolphin_state.h" #include "dolphin/dolphin.h" @@ -23,6 +22,7 @@ #include #include #include +#include #include #define XTREME_SUBGHZ_FREQ_BUFFER_SIZE 6 @@ -52,7 +52,7 @@ typedef struct { char subghz_freq_buffer[XTREME_SUBGHZ_FREQ_BUFFER_SIZE]; bool subghz_extend; bool subghz_bypass; - char device_name[NAMECHANGER_TEXT_STORE_SIZE]; + char device_name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; int32_t xp_level; FuriString* version_tag; diff --git a/applications/services/application.fam b/applications/services/application.fam index af02ef1a1..03bd4f8c1 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -10,6 +10,5 @@ App( "loader", "power", "rgb_backlight", - "namechangersrv", ], ) diff --git a/applications/services/namechangersrv/application.fam b/applications/services/namechangersrv/application.fam deleted file mode 100644 index 3263a3708..000000000 --- a/applications/services/namechangersrv/application.fam +++ /dev/null @@ -1,7 +0,0 @@ -App( - appid="namechangersrv", - apptype=FlipperAppType.STARTUP, - entry_point="namechanger_on_system_start", - requires=["storage"], - order=1000, -) diff --git a/applications/services/namechangersrv/namechangersrv.c b/applications/services/namechangersrv/namechangersrv.c deleted file mode 100644 index 33aeb3fdd..000000000 --- a/applications/services/namechangersrv/namechangersrv.c +++ /dev/null @@ -1,163 +0,0 @@ -#include "namechangersrv.h" -#include "m-string.h" -#include -#include - -void namechanger_on_system_start() { - if(!furi_hal_is_normal_boot()) { - FURI_LOG_W(TAG, "NameChangerSRV load skipped. Device is in special startup mode."); - } else { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); - - FuriString* NAMEHEADER; - NAMEHEADER = furi_string_alloc_set("Flipper Name File"); - - bool result = false; - - FuriString* data; - data = furi_string_alloc(); - - do { - if(!flipper_format_file_open_existing(file, NAMECHANGER_PATH)) { - break; - } - - // header - uint32_t version; - - if(!flipper_format_read_header(file, data, &version)) { - break; - } - - if(furi_string_cmp_str(data, furi_string_get_cstr(NAMEHEADER)) != 0) { - break; - } - - if(version != 1) { - break; - } - - // get Name - if(!flipper_format_read_string(file, "Name", data)) { - break; - } - - result = true; - } while(false); - - flipper_format_free(file); - - if(!result) { - //file not good - write new one - FlipperFormat* file = flipper_format_file_alloc(storage); - - bool res = false; - - do { - // Open file for write - if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) { - break; - } - - // Write header - if(!flipper_format_write_header_cstr(file, furi_string_get_cstr(NAMEHEADER), 1)) { - break; - } - - // Write comments - if(!flipper_format_write_comment_cstr( - file, - "Changing the value below will change your FlipperZero device name.")) { - break; - } - - if(!flipper_format_write_comment_cstr( - file, - "Note: This is limited to 8 characters using the following: a-z, A-Z, 0-9, and _")) { - break; - } - - if(!flipper_format_write_comment_cstr( - file, "It can contain other characters but use at your own risk.")) { - break; - } - - //Write name - if(!flipper_format_write_string_cstr( - file, "Name", furi_hal_version_get_name_ptr())) { - break; - } - - res = true; - } while(false); - - flipper_format_free(file); - - if(!res) { - FURI_LOG_E(TAG, "Save failed."); - } - } else { - if(!furi_string_size(data)) { - //Empty file - get default name and write to file. - FlipperFormat* file = flipper_format_file_alloc(storage); - - bool res = false; - - do { - // Open file for write - if(!flipper_format_file_open_always(file, NAMECHANGER_PATH)) { - break; - } - - // Write header - if(!flipper_format_write_header_cstr( - file, furi_string_get_cstr(NAMEHEADER), 1)) { - break; - } - - // Write comments - if(!flipper_format_write_comment_cstr( - file, - "Changing the value below will change your FlipperZero device name.")) { - break; - } - - if(!flipper_format_write_comment_cstr( - file, - "Note: This is limited to 8 characters using the following: a-z, A-Z, 0-9, and _")) { - break; - } - - if(!flipper_format_write_comment_cstr( - file, "It cannot contain any other characters.")) { - break; - } - - //Write name - if(!flipper_format_write_string_cstr( - file, "Name", furi_hal_version_get_name_ptr())) { - break; - } - - res = true; - } while(false); - - flipper_format_free(file); - - if(!res) { - FURI_LOG_E(TAG, "Save failed."); - } - } else { - char newdata[9]; - snprintf(newdata, 9, "%s", furi_string_get_cstr(data)); - //set name from file - furi_hal_version_set_custom_name(newdata); - } - } - - furi_string_free(data); - - furi_record_close(RECORD_STORAGE); - } -} diff --git a/applications/services/namechangersrv/namechangersrv.h b/applications/services/namechangersrv/namechangersrv.h deleted file mode 100644 index d440b19bc..000000000 --- a/applications/services/namechangersrv/namechangersrv.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include - -#define NAMECHANGER_TEXT_STORE_SIZE 9 -#define NAMECHANGER_HEADER "Flipper Name File" -#define NAMECHANGER_PATH EXT_PATH("dolphin/name.txt") - -#define TAG "NameChangerSRV" diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index b1dfb9afe..824dee830 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1535,7 +1535,7 @@ Function,+,furi_hal_version_get_model_name,const char*, Function,+,furi_hal_version_get_name_ptr,const char*, Function,+,furi_hal_version_get_otp_version,FuriHalVersionOtpVersion, Function,-,furi_hal_version_init,void, -Function,+,furi_hal_version_set_custom_name,void,const char* +Function,-,furi_hal_version_set_name,void,const char* Function,+,furi_hal_version_uid,const uint8_t*, Function,+,furi_hal_version_uid_size,size_t, Function,-,furi_hal_vibro_init,void, diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 43a48d136..32cf5386d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -90,26 +90,13 @@ typedef struct { static FuriHalVersion furi_hal_version = {0}; -void furi_hal_version_set_custom_name(const char* name) { - if((name != NULL) && ((strlen(name) >= 1) && (strlen(name) <= 8))) { +void furi_hal_version_set_name(const char* name) { + if(name != NULL && strlen(name)) { strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); snprintf( furi_hal_version.device_name, FURI_HAL_VERSION_DEVICE_NAME_LENGTH, - "x%s", // Someone tell me why that X is needed - name); - - furi_hal_version.device_name[0] = AD_TYPE_COMPLETE_LOCAL_NAME; - } -} - -static void furi_hal_version_set_name(const char* name) { - if(name != NULL) { - strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); - snprintf( - furi_hal_version.device_name, - FURI_HAL_VERSION_DEVICE_NAME_LENGTH, - "x%s", // Someone tell me why that X is needed + "x%s", // Someone tell me why that X is needed - it's for BLE adv name type (6 lines below) furi_hal_version.name); } else { snprintf(furi_hal_version.device_name, FURI_HAL_VERSION_DEVICE_NAME_LENGTH, "xFlipper"); @@ -119,8 +106,8 @@ static void furi_hal_version_set_name(const char* name) { // BLE Mac address uint32_t udn = LL_FLASH_GetUDN(); - if(version_get_custom_name(NULL) != NULL) { - udn = *((uint32_t*)version_get_custom_name(NULL)); + if(name != NULL) { + udn = *((uint32_t*)name); } uint32_t company_id = LL_FLASH_GetSTCompanyID(); diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index 2ff6730f6..3c1755512 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -159,7 +159,7 @@ FuriHalVersionDisplay furi_hal_version_get_hw_display(); uint32_t furi_hal_version_get_hw_timestamp(); // Set custom name -void furi_hal_version_set_custom_name(const char* name); +void furi_hal_version_set_name(const char* name); /** Get pointer to target name * diff --git a/furi/flipper.c b/furi/flipper.c index 1b13d8bf1..d2b4f9047 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -33,11 +33,11 @@ void flipper_start_service(const FlipperApplication* service) { FuriThread* thread = furi_thread_alloc_ex(service->name, service->stack_size, service->app, NULL); - furi_thread_mark_as_service(thread); + furi_thread_mark_as_service(thread); furi_thread_set_appid(thread, service->appid); - furi_thread_start(thread); - } + furi_thread_start(thread); +} void flipper_init() { flipper_print_version("Firmware", furi_hal_version_get_firmware_version()); @@ -47,6 +47,7 @@ void flipper_init() { // Start storage service first, thanks OFW :/ flipper_start_service(&FLIPPER_SERVICES[0]); + NAMESPOOF_INIT(); XTREME_SETTINGS_LOAD(); XTREME_ASSETS_LOAD(); diff --git a/lib/xtreme/namespoof.c b/lib/xtreme/namespoof.c new file mode 100644 index 000000000..9785700dd --- /dev/null +++ b/lib/xtreme/namespoof.c @@ -0,0 +1,26 @@ +#include "namespoof.h" +#include +#include + +#define TAG "NameSpoof" + +void NAMESPOOF_INIT() { + FuriString* str = furi_string_alloc(); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + + do { + uint32_t version; + if(!flipper_format_file_open_existing(file, NAMESPOOF_PATH)) break; + if(!flipper_format_read_header(file, str, &version)) break; + if(furi_string_cmp_str(str, NAMESPOOF_HEADER)) break; + if(version != NAMESPOOF_VERSION) break; + + if(!flipper_format_read_string(file, "Name", str)) break; + furi_hal_version_set_name(furi_string_get_cstr(str)); + } while(false); + + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); + furi_string_free(str); +} diff --git a/lib/xtreme/namespoof.h b/lib/xtreme/namespoof.h new file mode 100644 index 000000000..5d7e91a1f --- /dev/null +++ b/lib/xtreme/namespoof.h @@ -0,0 +1,5 @@ +#pragma once + +#define NAMESPOOF_HEADER "Flipper Name File" +#define NAMESPOOF_VERSION 1 +#define NAMESPOOF_PATH EXT_PATH("dolphin/name.txt") diff --git a/lib/xtreme/private.h b/lib/xtreme/private.h index d1644c3e3..2718b67af 100644 --- a/lib/xtreme/private.h +++ b/lib/xtreme/private.h @@ -1,4 +1,5 @@ #pragma once +void NAMESPOOF_INIT(); void XTREME_SETTINGS_LOAD(); void XTREME_ASSETS_LOAD(); From 4aef6a9df825004603ff0d8eb2a7c715fe8a7fac Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 12:57:31 +0100 Subject: [PATCH 184/216] Move rgb backlight from useless service to lib --- applications/main/xtreme_app/xtreme_app.h | 2 +- applications/services/application.fam | 1 - applications/services/rgb_backlight/application.fam | 10 ---------- applications/services/storage/application.fam | 2 +- applications/system/updater/application.fam | 1 - firmware/targets/f7/api_symbols.csv | 2 +- firmware/targets/f7/furi_hal/furi_hal_light.c | 2 +- lib/drivers/SConscript | 3 +++ .../rgb_backlight => lib/drivers}/rgb_backlight.c | 5 ----- .../rgb_backlight => lib/drivers}/rgb_backlight.h | 0 10 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 applications/services/rgb_backlight/application.fam rename {applications/services/rgb_backlight => lib/drivers}/rgb_backlight.c (98%) rename {applications/services/rgb_backlight => lib/drivers}/rgb_backlight.h (100%) diff --git a/applications/main/xtreme_app/xtreme_app.h b/applications/main/xtreme_app/xtreme_app.h index f7d79249d..542353338 100644 --- a/applications/main/xtreme_app/xtreme_app.h +++ b/applications/main/xtreme_app/xtreme_app.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/applications/services/application.fam b/applications/services/application.fam index 03bd4f8c1..aec49b231 100644 --- a/applications/services/application.fam +++ b/applications/services/application.fam @@ -9,6 +9,5 @@ App( "desktop", "loader", "power", - "rgb_backlight", ], ) diff --git a/applications/services/rgb_backlight/application.fam b/applications/services/rgb_backlight/application.fam deleted file mode 100644 index 20b7d0fed..000000000 --- a/applications/services/rgb_backlight/application.fam +++ /dev/null @@ -1,10 +0,0 @@ -App( - appid="rgb_backlight", - name="RGB Backlight", - apptype=FlipperAppType.SERVICE, - entry_point="rgb_backlight_srv", - order=10, - sdk_headers=[ - "rgb_backlight.h", - ], -) diff --git a/applications/services/storage/application.fam b/applications/services/storage/application.fam index 89fa48e63..260609c5c 100644 --- a/applications/services/storage/application.fam +++ b/applications/services/storage/application.fam @@ -7,7 +7,7 @@ App( requires=["storage_settings"], provides=["storage_start"], stack_size=3 * 1024, - order=0, + order=10, sdk_headers=["storage.h"], ) diff --git a/applications/system/updater/application.fam b/applications/system/updater/application.fam index bdbb69fda..b3f6603da 100644 --- a/applications/system/updater/application.fam +++ b/applications/system/updater/application.fam @@ -6,7 +6,6 @@ App( requires=[ "gui", "storage", - "rgb_backlight", "archive", ], conflicts=["desktop"], diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 824dee830..be24dd5ed 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -37,7 +37,6 @@ Header,+,applications/services/locale/locale.h,, Header,+,applications/services/notification/notification.h,, Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, -Header,+,applications/services/rgb_backlight/rgb_backlight.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, @@ -117,6 +116,7 @@ Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, Header,-,lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h,, Header,+,lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h,, +Header,+,lib/drivers/rgb_backlight.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c index 5ce624d1e..76b401d95 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_light.c +++ b/firmware/targets/f7/furi_hal/furi_hal_light.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define LED_CURRENT_RED 50 #define LED_CURRENT_GREEN 50 diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index 3b7ee2401..7cbd42b37 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/drivers", ], + SDK_HEADERS=[ + File("rgb_backlight.h"), + ], ) diff --git a/applications/services/rgb_backlight/rgb_backlight.c b/lib/drivers/rgb_backlight.c similarity index 98% rename from applications/services/rgb_backlight/rgb_backlight.c rename to lib/drivers/rgb_backlight.c index 9b39b469a..ec39efb0b 100644 --- a/applications/services/rgb_backlight/rgb_backlight.c +++ b/lib/drivers/rgb_backlight.c @@ -172,8 +172,3 @@ void rgb_backlight_update(uint8_t brightness) { SK6805_update(); } - -int32_t rgb_backlight_srv(void* p) { - UNUSED(p); - return 0; -} diff --git a/applications/services/rgb_backlight/rgb_backlight.h b/lib/drivers/rgb_backlight.h similarity index 100% rename from applications/services/rgb_backlight/rgb_backlight.h rename to lib/drivers/rgb_backlight.h From d18623383c8a456089b24063c5dfa6bcae2a8345 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 13:34:44 +0100 Subject: [PATCH 185/216] Fix bt keys shenanigans --- applications/external/hid_app/hid.h | 2 +- applications/external/hid_app/hid_path.h | 3 +++ applications/main/bad_kb/bad_kb_app.c | 5 +---- applications/main/bad_kb/bad_kb_app.h | 3 +-- applications/main/bad_kb/bad_kb_paths.h | 8 ++++++++ applications/main/bad_kb/bad_kb_settings_filename.h | 7 ------- applications/main/bad_kb/helpers/ducky_script.c | 2 -- .../scenes/bt_settings_scene_forget_dev_confirm.c | 10 +++++++--- 8 files changed, 21 insertions(+), 19 deletions(-) create mode 100644 applications/external/hid_app/hid_path.h create mode 100644 applications/main/bad_kb/bad_kb_paths.h delete mode 100644 applications/main/bad_kb/bad_kb_settings_filename.h diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 1a533de99..472200683 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -27,7 +27,7 @@ #include "views/hid_ytshorts.h" #include "views/hid_mouse_clicker.h" -#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" +#include "hid_path.h" typedef enum { HidTransportUsb, diff --git a/applications/external/hid_app/hid_path.h b/applications/external/hid_app/hid_path.h new file mode 100644 index 000000000..ed4ec45ff --- /dev/null +++ b/applications/external/hid_app/hid_path.h @@ -0,0 +1,3 @@ +#pragma once + +#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c index 205a14022..e93644a3f 100644 --- a/applications/main/bad_kb/bad_kb_app.c +++ b/applications/main/bad_kb/bad_kb_app.c @@ -1,5 +1,4 @@ #include "bad_kb_app.h" -#include "bad_kb_settings_filename.h" #include #include #include @@ -11,8 +10,6 @@ #include #include -#define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/" BAD_KB_SETTINGS_FILE_NAME - static bool bad_kb_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); BadKbApp* app = context; @@ -138,7 +135,7 @@ int32_t bad_kb_connection_init(BadKbApp* app) { bt_timeout = bt_hid_delays[LevelRssi39_0]; bt_disconnect(app->bt); - bt_keys_storage_set_storage_path(app->bt, BAD_KB_APP_PATH_BOUND_KEYS_FILE); + bt_keys_storage_set_storage_path(app->bt, BAD_KB_KEYS_PATH); if(strcmp(app->config.bt_name, "") != 0) { furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->config.bt_name); } diff --git a/applications/main/bad_kb/bad_kb_app.h b/applications/main/bad_kb/bad_kb_app.h index 923ba7780..20bc87ce4 100644 --- a/applications/main/bad_kb/bad_kb_app.h +++ b/applications/main/bad_kb/bad_kb_app.h @@ -1,6 +1,7 @@ #pragma once #include "bad_kb_app.h" +#include "bad_kb_paths.h" #include "scenes/bad_kb_scene.h" #include "helpers/ducky_script.h" @@ -10,8 +11,6 @@ #include #include -#define BAD_KB_APP_BASE_FOLDER EXT_PATH("badkb") -#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts" #define BAD_KB_APP_SCRIPT_EXTENSION ".txt" #define BAD_KB_APP_LAYOUT_EXTENSION ".kl" diff --git a/applications/main/bad_kb/bad_kb_paths.h b/applications/main/bad_kb/bad_kb_paths.h new file mode 100644 index 000000000..72685b905 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_paths.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#define BAD_KB_APP_BASE_FOLDER EXT_PATH("badkb") +#define BAD_KB_KEYS_PATH BAD_KB_APP_BASE_FOLDER "/.badkb.keys" +#define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/.badkb.settings" +#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts" diff --git a/applications/main/bad_kb/bad_kb_settings_filename.h b/applications/main/bad_kb/bad_kb_settings_filename.h deleted file mode 100644 index 42de4878a..000000000 --- a/applications/main/bad_kb/bad_kb_settings_filename.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -#define BAD_KB_SETTINGS_FILE_NAME ".badkb.settings" -#define BAD_KB_APP_PATH_BOUND_KEYS_FOLDER EXT_PATH("badkb/.bt_keys") -#define BAD_KB_APP_PATH_BOUND_KEYS_FILE BAD_KB_APP_PATH_BOUND_KEYS_FOLDER "/.devices.keys" diff --git a/applications/main/bad_kb/helpers/ducky_script.c b/applications/main/bad_kb/helpers/ducky_script.c index d41f4ea41..0c2bbf5d6 100644 --- a/applications/main/bad_kb/helpers/ducky_script.c +++ b/applications/main/bad_kb/helpers/ducky_script.c @@ -23,8 +23,6 @@ const uint8_t BAD_KB_EMPTY_MAC_ADDRESS[BAD_KB_MAC_ADDRESS_LEN] = #define BADKB_ASCII_TO_KEY(script, x) \ (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) -#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys") - /** * Delays for waiting between HID key press and key release */ diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c index 00ddca333..e39e5a737 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c @@ -1,6 +1,7 @@ #include "../bt_settings_app.h" #include -#include +#include +#include void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) { furi_assert(context); @@ -31,8 +32,11 @@ bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEv consumed = scene_manager_previous_scene(app->scene_manager); } else if(event.event == DialogExResultRight) { bt_forget_bonded_devices(app->bt); - // also removes keys of badkb bonded devices - bt_keys_storage_set_storage_path(app->bt, BAD_KB_APP_PATH_BOUND_KEYS_FILE); + // also remove keys of badkb and bt remote + bt_keys_storage_set_storage_path(app->bt, BAD_KB_KEYS_PATH); + bt_forget_bonded_devices(app->bt); + bt_keys_storage_set_storage_path( + app->bt, EXT_PATH("apps_data/hid_ble") "/" HID_BT_KEYS_STORAGE_NAME); bt_forget_bonded_devices(app->bt); bt_keys_storage_set_default_path(app->bt); From b0b94c70e0e80d4e57cde6f17d79ec966409e7d6 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 13:56:39 +0100 Subject: [PATCH 186/216] Fix forgetting badkb and bt remote keys --- .../scenes/bt_settings_scene_forget_dev_confirm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c index e39e5a737..ff5989245 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c @@ -31,14 +31,15 @@ bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEv if(event.event == DialogExResultLeft) { consumed = scene_manager_previous_scene(app->scene_manager); } else if(event.event == DialogExResultRight) { - bt_forget_bonded_devices(app->bt); - // also remove keys of badkb and bt remote - bt_keys_storage_set_storage_path(app->bt, BAD_KB_KEYS_PATH); - bt_forget_bonded_devices(app->bt); - bt_keys_storage_set_storage_path( - app->bt, EXT_PATH("apps_data/hid_ble") "/" HID_BT_KEYS_STORAGE_NAME); - bt_forget_bonded_devices(app->bt); bt_keys_storage_set_default_path(app->bt); + bt_forget_bonded_devices(app->bt); + + // also remove keys of badkb and bt remote + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_simply_remove(storage, BAD_KB_KEYS_PATH); + storage_simply_remove( + storage, EXT_PATH("apps_data/hid_ble/") HID_BT_KEYS_STORAGE_NAME); + furi_record_close(RECORD_STORAGE); scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevSuccess); consumed = true; From 5c3bd23871c2a51014d3cb539f2c04df7bc85c97 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 14:31:11 +0100 Subject: [PATCH 187/216] Notif settings on external, begone goofy load/save --- .../services/notification/notification_app.c | 94 ++++++------------- .../services/notification/notification_app.h | 5 +- .../notification_settings_filename.h | 3 - lib/update_util/lfs_backup.c | 22 +---- 4 files changed, 31 insertions(+), 93 deletions(-) delete mode 100644 applications/services/notification/notification_settings_filename.h diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 76dc2e052..61be402bd 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "notification.h" #include "notification_messages.h" @@ -410,78 +411,37 @@ void notification_process_internal_message(NotificationApp* app, NotificationApp } } -static bool notification_load_settings(NotificationApp* app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); - - FURI_LOG_I(TAG, "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH); - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - - if(fs_result) { - uint16_t bytes_count = storage_file_read(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; - } - } - - if(fs_result) { - FURI_LOG_I(TAG, "load success"); - - if(settings.version != NOTIFICATION_SETTINGS_VERSION) { - FURI_LOG_E( - TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); - } else { - furi_kernel_lock(); - memcpy(&app->settings, &settings, settings_size); - furi_kernel_unlock(); - } - } else { - FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file)); - } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return fs_result; +static bool notification_save_settings(NotificationApp* app) { + return saved_struct_save( + NOTIFICATION_SETTINGS_PATH, + &app->settings, + sizeof(NotificationSettings), + NOTIFICATION_SETTINGS_MAGIC, + NOTIFICATION_SETTINGS_VERSION); } -static bool notification_save_settings(NotificationApp* app) { - NotificationSettings settings; - File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - const size_t settings_size = sizeof(NotificationSettings); +static bool notification_load_settings(NotificationApp* app) { + bool ret = saved_struct_load( + NOTIFICATION_SETTINGS_PATH, + &app->settings, + sizeof(NotificationSettings), + NOTIFICATION_SETTINGS_MAGIC, + NOTIFICATION_SETTINGS_VERSION); - FURI_LOG_I(TAG, "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH); - - furi_kernel_lock(); - memcpy(&settings, &app->settings, settings_size); - furi_kernel_unlock(); - - bool fs_result = - storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); - - if(fs_result) { - uint16_t bytes_count = storage_file_write(file, &settings, settings_size); - - if(bytes_count != settings_size) { - fs_result = false; - } + if(!ret) { + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_common_copy(storage, NOTIFICATION_SETTINGS_OLD_PATH, NOTIFICATION_SETTINGS_PATH); + storage_common_remove(storage, NOTIFICATION_SETTINGS_OLD_PATH); + furi_record_close(RECORD_STORAGE); + ret = saved_struct_load( + NOTIFICATION_SETTINGS_PATH, + &app->settings, + sizeof(NotificationSettings), + NOTIFICATION_SETTINGS_MAGIC, + NOTIFICATION_SETTINGS_VERSION); } - if(fs_result) { - FURI_LOG_I(TAG, "save success"); - } else { - FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); - } - - storage_file_close(file); - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - - return fs_result; + return ret; } static void input_event_callback(const void* value, void* context) { diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 88194bfbd..92a668ee9 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -2,7 +2,6 @@ #include #include "notification.h" #include "notification_messages.h" -#include "notification_settings_filename.h" #define NOTIFICATION_LED_COUNT 3 #define NOTIFICATION_EVENT_COMPLETE 0x00000001U @@ -33,7 +32,9 @@ typedef struct { } NotificationLedLayer; #define NOTIFICATION_SETTINGS_VERSION 0x01 -#define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) +#define NOTIFICATION_SETTINGS_MAGIC 0x16 +#define NOTIFICATION_SETTINGS_OLD_PATH INT_PATH(".notification.settings") +#define NOTIFICATION_SETTINGS_PATH CFG_PATH("notification.settings") typedef struct { uint8_t version; diff --git a/applications/services/notification/notification_settings_filename.h b/applications/services/notification/notification_settings_filename.h deleted file mode 100644 index d9ed596ec..000000000 --- a/applications/services/notification/notification_settings_filename.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define NOTIFICATION_SETTINGS_FILE_NAME ".notification.settings" diff --git a/lib/update_util/lfs_backup.c b/lib/update_util/lfs_backup.c index b299a9d32..a441ccabd 100644 --- a/lib/update_util/lfs_backup.c +++ b/lib/update_util/lfs_backup.c @@ -2,28 +2,8 @@ #include -#include - #define LFS_BACKUP_DEFAULT_LOCATION EXT_PATH(LFS_BACKUP_DEFAULT_FILENAME) -static void backup_name_converter(FuriString* filename) { - if(furi_string_empty(filename) || (furi_string_get_char(filename, 0) == '.')) { - return; - } - - /* Filenames are already prefixed with '.' */ - const char* const names[] = { - NOTIFICATION_SETTINGS_FILE_NAME, - }; - - for(size_t i = 0; i < COUNT_OF(names); i++) { - if(furi_string_equal(filename, &names[i][1])) { - furi_string_set(filename, names[i]); - return; - } - } -} - bool lfs_backup_create(Storage* storage, const char* destination) { const char* final_destination = destination && strlen(destination) ? destination : LFS_BACKUP_DEFAULT_LOCATION; @@ -37,5 +17,5 @@ bool lfs_backup_exists(Storage* storage, const char* source) { bool lfs_backup_unpack(Storage* storage, const char* source) { const char* final_source = source && strlen(source) ? source : LFS_BACKUP_DEFAULT_LOCATION; - return storage_int_restore(storage, final_source, backup_name_converter) == FSE_OK; + return storage_int_restore(storage, final_source, NULL) == FSE_OK; } From 45382331f756452196757a4b7aaf3a3c8b2aa5f5 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 16:14:00 +0100 Subject: [PATCH 188/216] Revert copro update --- lib/stm32wb_copro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stm32wb_copro b/lib/stm32wb_copro index 6c9c54f05..d685979c2 160000 --- a/lib/stm32wb_copro +++ b/lib/stm32wb_copro @@ -1 +1 @@ -Subproject commit 6c9c54f05669b2c4d436df58bb691d3b0d7c86df +Subproject commit d685979c282c9f38d561dd1ea8e6fdbd735d7362 From 5b710bf488aa8391b45b5b5642b4eaeb2ed1508e Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 16:29:36 +0100 Subject: [PATCH 189/216] Update copro symbols --- firmware/targets/f7/api_symbols.csv | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index f782d4ab2..e9ea9a80e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -218,17 +218,17 @@ Header,+,lib/toolbox/version.h,, Header,+,lib/u8g2/u8g2.h,, Header,+,lib/xtreme/xtreme.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* -Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" +Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* -Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" +Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_INJ_InitTypeDef*" Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* -Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" -Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" +Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" +Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_REG_InitTypeDef*" Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* -Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" +Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, const LL_COMP_InitTypeDef*" Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* Function,-,LL_CRS_DeInit,ErrorStatus, @@ -247,10 +247,10 @@ Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* Function,-,LL_Init1msTick,void,uint32_t Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* -Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" +Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, const LL_LPTIM_InitTypeDef*" Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* -Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" +Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" @@ -295,23 +295,23 @@ Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t Function,+,LL_SetSystemCoreClock,void,uint32_t -Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" +Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_BDTR_InitTypeDef*" Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* -Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" +Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_ENCODER_InitTypeDef*" Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* -Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" +Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_HALLSENSOR_InitTypeDef*" Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* -Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" +Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_IC_InitTypeDef*" Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* -Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" -Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" +Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" +Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_OC_InitTypeDef*" Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* -Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" +Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, const LL_USART_ClockInitTypeDef*" Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* -Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" +Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* Function,-,LL_mDelay,void,uint32_t Function,-,SK6805_get_led_count,uint8_t, From bb7dc8ce22442e4597ebb29e764dd04ccd057570 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 19:11:35 +0100 Subject: [PATCH 190/216] BadKB lock relevant configs with ID and BT_ID cmds --- applications/main/bad_kb/bad_kb_app.c | 6 ++- .../main/bad_kb/helpers/ducky_script.c | 19 ++++---- .../main/bad_kb/helpers/ducky_script.h | 7 +++ .../main/bad_kb/scenes/bad_kb_scene_config.c | 48 +++++++++++-------- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c index e93644a3f..03b941cd3 100644 --- a/applications/main/bad_kb/bad_kb_app.c +++ b/applications/main/bad_kb/bad_kb_app.c @@ -102,9 +102,13 @@ int32_t bad_kb_config_switch_mode(BadKbApp* app) { XTREME_SETTINGS_SAVE(); bad_kb_reload_worker(app); if(app->is_bt) furi_hal_bt_start_advertising(); + bad_kb_config_refresh_menu(app); + return 0; +} + +void bad_kb_config_refresh_menu(BadKbApp* app) { scene_manager_next_scene(app->scene_manager, BadKbSceneConfig); scene_manager_previous_scene(app->scene_manager); - return 0; } void bad_kb_config_switch_remember_mode(BadKbApp* app) { diff --git a/applications/main/bad_kb/helpers/ducky_script.c b/applications/main/bad_kb/helpers/ducky_script.c index 0c2bbf5d6..99754c5fe 100644 --- a/applications/main/bad_kb/helpers/ducky_script.c +++ b/applications/main/bad_kb/helpers/ducky_script.c @@ -386,9 +386,11 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { bad_kb->app->switch_mode_thread = NULL; } // Looking for ID or BT_ID command at first line - bool usb_id = false; - bool bt_id = false; - if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + bad_kb->set_usb_id = false; + bad_kb->set_bt_id = false; + bad_kb->has_usb_id = strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0; + bad_kb->has_bt_id = strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0; + if(bad_kb->has_usb_id) { if(bad_kb->bt) { bad_kb->app->is_bt = false; bad_kb->app->switch_mode_thread = furi_thread_alloc_ex( @@ -399,8 +401,8 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { furi_thread_start(bad_kb->app->switch_mode_thread); return false; } - usb_id = ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1]); - } else if(strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0) { + bad_kb->set_usb_id = ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1]); + } else if(bad_kb->has_bt_id) { if(!bad_kb->bt) { bad_kb->app->is_bt = true; bad_kb->app->switch_mode_thread = furi_thread_alloc_ex( @@ -412,12 +414,13 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { return false; } if(!bad_kb->app->bt_remember) { - bt_id = ducky_set_bt_id(bad_kb, &line_tmp[strlen(ducky_cmd_bt_id) + 1]); + bad_kb->set_bt_id = ducky_set_bt_id(bad_kb, &line_tmp[strlen(ducky_cmd_bt_id) + 1]); } } + bad_kb_config_refresh_menu(bad_kb->app); if(bad_kb->bt) { - if(!bt_id) { + if(!bad_kb->set_bt_id) { const char* bt_name = bad_kb->app->config.bt_name; const uint8_t* bt_mac = bad_kb->app->bt_remember ? (uint8_t*)&BAD_KB_BOUND_MAC_ADDRESS : @@ -440,7 +443,7 @@ static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { } } } else { - if(usb_id) { + if(bad_kb->set_usb_id) { furi_check(furi_hal_usb_set_config(&usb_hid, &bad_kb->hid_cfg)); } else { furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); diff --git a/applications/main/bad_kb/helpers/ducky_script.h b/applications/main/bad_kb/helpers/ducky_script.h index 015586b2e..6c0098524 100644 --- a/applications/main/bad_kb/helpers/ducky_script.h +++ b/applications/main/bad_kb/helpers/ducky_script.h @@ -82,6 +82,11 @@ typedef struct { FuriString* string_print; size_t string_print_pos; + bool set_usb_id; + bool set_bt_id; + bool has_usb_id; + bool has_bt_id; + Bt* bt; BadKbApp* app; } BadKbScript; @@ -147,6 +152,8 @@ struct BadKbApp { int32_t bad_kb_config_switch_mode(BadKbApp* app); +void bad_kb_config_refresh_menu(BadKbApp* app); + #ifdef __cplusplus } #endif diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config.c b/applications/main/bad_kb/scenes/bad_kb_scene_config.c index 3f16a4c48..e029d052e 100644 --- a/applications/main/bad_kb/scenes/bad_kb_scene_config.c +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config.c @@ -45,28 +45,36 @@ void bad_kb_scene_config_on_enter(void* context) { var_item_list, "Connection", 2, bad_kb_scene_config_connection_callback, bad_kb); variable_item_set_current_value_index(item, bad_kb->is_bt); variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); - - item = variable_item_list_add( - var_item_list, "BT Remember", 2, bad_kb_scene_config_bt_remember_callback, bad_kb); - variable_item_set_current_value_index(item, bad_kb->bt_remember); - variable_item_set_current_value_text(item, bad_kb->bt_remember ? "ON" : "OFF"); - variable_item_set_locked(item, !bad_kb->is_bt, "Only in\nBT mode!"); - - item = variable_item_list_add(var_item_list, "BT Device Name", 0, NULL, bad_kb); - variable_item_set_locked(item, !bad_kb->is_bt, "Only in\nBT mode!"); - - item = variable_item_list_add(var_item_list, "BT MAC Address", 0, NULL, bad_kb); - if(!bad_kb->is_bt) { - variable_item_set_locked(item, true, "Only in\nBT mode!"); - } else if(bad_kb->bt_remember) { - variable_item_set_locked(item, true, "Remember\nmust be Off!"); + if(bad_kb->bad_kb_script->has_usb_id) { + variable_item_set_locked(item, true, "Script has\nID cmd!\nLocked to\nUSB Mode!"); + } else if(bad_kb->bad_kb_script->has_bt_id) { + variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nBT Mode!"); } - item = variable_item_list_add(var_item_list, "Randomize BT MAC", 0, NULL, bad_kb); - if(!bad_kb->is_bt) { - variable_item_set_locked(item, true, "Only in\nBT mode!"); - } else if(bad_kb->bt_remember) { - variable_item_set_locked(item, true, "Remember\nmust be Off!"); + if(bad_kb->is_bt) { + item = variable_item_list_add( + var_item_list, "BT Remember", 2, bad_kb_scene_config_bt_remember_callback, bad_kb); + variable_item_set_current_value_index(item, bad_kb->bt_remember); + variable_item_set_current_value_text(item, bad_kb->bt_remember ? "ON" : "OFF"); + + item = variable_item_list_add(var_item_list, "BT Device Name", 0, NULL, bad_kb); + if(bad_kb->bad_kb_script->set_bt_id) { + variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset Name!"); + } + + item = variable_item_list_add(var_item_list, "BT MAC Address", 0, NULL, bad_kb); + if(bad_kb->bt_remember) { + variable_item_set_locked(item, true, "Remember\nmust be Off!"); + } else if(bad_kb->bad_kb_script->set_bt_id) { + variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!"); + } + + item = variable_item_list_add(var_item_list, "Randomize BT MAC", 0, NULL, bad_kb); + if(bad_kb->bt_remember) { + variable_item_set_locked(item, true, "Remember\nmust be Off!"); + } else if(bad_kb->bad_kb_script->set_bt_id) { + variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!"); + } } variable_item_list_set_enter_callback( From 1db415788618cb7c4eb99a50058b041f988b0f63 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 19:12:34 +0100 Subject: [PATCH 191/216] Namespoof also spoof serial number --- firmware/targets/f7/api_symbols.csv | 1 + lib/toolbox/version.c | 8 +++++++- lib/toolbox/version.h | 8 ++++++++ lib/xtreme/namespoof.c | 3 ++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e9ea9a80e..22b419d7b 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -4669,6 +4669,7 @@ Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* Function,+,version_get_target,uint8_t,const Version* Function,+,version_get_version,const char*,const Version* +Function,-,version_set_custom_name,void,"Version*, const char*" Function,-,vfiprintf,int,"FILE*, const char*, __gnuc_va_list" Function,-,vfiscanf,int,"FILE*, const char*, __gnuc_va_list" Function,-,vfprintf,int,"FILE*, const char*, __gnuc_va_list" diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index e0a6e6197..69c43b8bf 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -24,7 +24,7 @@ struct Version { }; /* version of current running firmware (bootloader/flipper) */ -static const Version version = { +static Version version = { .magic = VERSION_MAGIC, .major = VERSION_MAJOR, .minor = VERSION_MINOR, @@ -74,6 +74,12 @@ const char* version_get_custom_name(const Version* v) { return v ? v->custom_flipper_name : version.custom_flipper_name; } +void version_set_custom_name(Version* v, const char* name) { + Version* ver = v ? v : &version; + ver->custom_flipper_name = name; + return; +} + uint8_t version_get_target(const Version* v) { return v ? v->target : version.target; } diff --git a/lib/toolbox/version.h b/lib/toolbox/version.h index ed54631b3..43fe6a9d3 100644 --- a/lib/toolbox/version.h +++ b/lib/toolbox/version.h @@ -74,6 +74,14 @@ const char* version_get_version(const Version* v); */ const char* version_get_custom_name(const Version* v); +/** Get custom flipper name if set in ENV + * + * @param v pointer to Version data. NULL for currently running + * software. + * @param custom name or NULL + */ +void version_set_custom_name(Version* v, const char* name); + /** Get hardware target this firmware was built for * * @param v pointer to Version data. NULL for currently running diff --git a/lib/xtreme/namespoof.c b/lib/xtreme/namespoof.c index 9785700dd..3a5918a38 100644 --- a/lib/xtreme/namespoof.c +++ b/lib/xtreme/namespoof.c @@ -17,7 +17,8 @@ void NAMESPOOF_INIT() { if(version != NAMESPOOF_VERSION) break; if(!flipper_format_read_string(file, "Name", str)) break; - furi_hal_version_set_name(furi_string_get_cstr(str)); + version_set_custom_name(NULL, strdup(furi_string_get_cstr(str))); + furi_hal_version_set_name(version_get_custom_name(NULL)); } while(false); flipper_format_free(file); From 3bc95bc13275fb1501c90259f1da87bb912d2333 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 19:22:05 +0100 Subject: [PATCH 192/216] Format --- lib/pulse_reader/pulse_reader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 1d5fcb7a2..74d99fe80 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -209,8 +209,8 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { /* probably larger values, so choose a wider data type */ if(signal->unit_divider > 1) { - delta_unit = (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / - signal->unit_divider); + delta_unit = + (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider); } else { delta_unit = delta * signal->unit_multiplier; } From cca6606c7819fd4c3249172bb895a51a7030bcfd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 21:48:48 +0300 Subject: [PATCH 193/216] fix typos from ofw --- .../debug/unit_tests/subghz/subghz_test.c | 8 ++--- ...ey.c => subghz_txrx_create_protocol_key.c} | 4 +-- ...ey.h => subghz_txrx_create_protocol_key.h} | 2 +- .../subghz/scenes/subghz_scene_set_seed.c | 2 +- .../subghz/scenes/subghz_scene_set_type.c | 36 +++++++++---------- lib/subghz/protocols/keeloq_common.c | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) rename applications/main/subghz/helpers/{subghz_txrx_create_potocol_key.c => subghz_txrx_create_protocol_key.c} (98%) rename applications/main/subghz/helpers/{subghz_txrx_create_potocol_key.h => subghz_txrx_create_protocol_key.h} (98%) diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index c7e9c96f1..f1ab92653 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -407,7 +407,7 @@ MU_TEST(subghz_decoder_ido_test) { "Test decoder " SUBGHZ_PROTOCOL_IDO_NAME " error\r\n"); } -MU_TEST(subghz_decoder_keelog_test) { +MU_TEST(subghz_decoder_keeloq_test) { mu_assert( subghz_decoder_test( EXT_PATH("unit_tests/subghz/doorhan_raw.sub"), SUBGHZ_PROTOCOL_KEELOQ_NAME), @@ -676,7 +676,7 @@ MU_TEST(subghz_encoder_nice_flo_test) { "Test encoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n"); } -MU_TEST(subghz_encoder_keelog_test) { +MU_TEST(subghz_encoder_keeloq_test) { mu_assert( subghz_encoder_test(EXT_PATH("unit_tests/subghz/doorhan.sub")), "Test encoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n"); @@ -813,7 +813,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_gate_tx_test); MU_RUN_TEST(subghz_decoder_hormann_hsm_test); MU_RUN_TEST(subghz_decoder_ido_test); - MU_RUN_TEST(subghz_decoder_keelog_test); + MU_RUN_TEST(subghz_decoder_keeloq_test); MU_RUN_TEST(subghz_decoder_kia_seed_test); MU_RUN_TEST(subghz_decoder_nero_radio_test); MU_RUN_TEST(subghz_decoder_nero_sketch_test); @@ -852,7 +852,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_came_twee_test); MU_RUN_TEST(subghz_encoder_gate_tx_test); MU_RUN_TEST(subghz_encoder_nice_flo_test); - MU_RUN_TEST(subghz_encoder_keelog_test); + MU_RUN_TEST(subghz_encoder_keeloq_test); MU_RUN_TEST(subghz_encoder_linear_test); MU_RUN_TEST(subghz_encoder_linear_delta3_test); MU_RUN_TEST(subghz_encoder_megacode_test); diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c similarity index 98% rename from applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c rename to applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 7c3b1c7ff..7a0060f16 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -1,5 +1,5 @@ #include "subghz_txrx_i.h" -#include "subghz_txrx_create_potocol_key.h" +#include "subghz_txrx_create_protocol_key.h" #include #include #include @@ -84,7 +84,7 @@ bool subghz_txrx_gen_data_protocol_and_te( return ret; } -bool subghz_txrx_gen_keelog_protocol( //TODO lead to a general appearance +bool subghz_txrx_gen_keeloq_protocol( //TODO lead to a general appearance SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h similarity index 98% rename from applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h rename to applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 5aa8a31ac..96e592936 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -54,7 +54,7 @@ bool subghz_txrx_gen_data_protocol_and_te( * @param manufacture_name Name of Keeloq sysmem * @return bool True if success */ -bool subghz_txrx_gen_keelog_protocol( +bool subghz_txrx_gen_keeloq_protocol( SubGhzTxRx* instance, const char* preset_name, uint32_t frequency, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index d3537689d..18bc787bb 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -1,5 +1,5 @@ #include "../subghz_i.h" -#include "../helpers/subghz_txrx_create_potocol_key.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" #define TAG "SubGhzSetSeed" diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 076241767..342f01536 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,5 +1,5 @@ #include "../subghz_i.h" -#include "../helpers/subghz_txrx_create_potocol_key.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" #include #include @@ -367,7 +367,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexBeninca433: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, @@ -382,7 +382,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexBeninca868: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 868350000, @@ -397,7 +397,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAllmatic433: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, @@ -412,7 +412,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAllmatic868: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 868350000, @@ -427,7 +427,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexElmesElectronic: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, @@ -442,7 +442,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexANMotorsAT4: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, @@ -457,7 +457,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAprimatic: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, @@ -472,7 +472,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexGibidi433: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Gibidi"); if(!generated_protocol) { furi_string_set( @@ -481,7 +481,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexGSN: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "GSN"); if(!generated_protocol) { furi_string_set( @@ -490,7 +490,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexIronLogic: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFF0, 0x4, 0x0005, "IronLogic"); if(!generated_protocol) { furi_string_set( @@ -499,7 +499,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSommer_FM_434: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "FM476", 434420000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( @@ -508,7 +508,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSommer_FM_868: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "FM476", 868800000, key & 0x0FFFFFFF, 0x4, 0x0003, "Sommer(fsk476)"); if(!generated_protocol) { furi_string_set( @@ -517,7 +517,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDTMNeo433: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x000FFFFF, 0x2, 0x0005, "DTM_Neo"); if(!generated_protocol) { furi_string_set( @@ -526,7 +526,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexCAMESpace: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Came_Space"); if(!generated_protocol) { furi_string_set( @@ -569,7 +569,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_433_92: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( @@ -578,7 +578,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 315000000, key & 0x0FFFFFFF, 0x2, 0x0003, "DoorHan"); if(!generated_protocol) { furi_string_set( @@ -605,7 +605,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexNiceSmilo_433_92: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "NICE_Smilo"); if(!generated_protocol) { furi_string_set( diff --git a/lib/subghz/protocols/keeloq_common.c b/lib/subghz/protocols/keeloq_common.c index 1d2d04457..a9a2238dd 100644 --- a/lib/subghz/protocols/keeloq_common.c +++ b/lib/subghz/protocols/keeloq_common.c @@ -23,7 +23,7 @@ inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const } /** Simple Learning Decrypt - * @param data - keelog encrypt data + * @param data - keeloq encrypt data * @param key - manufacture (64bit) * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter */ From 735fe31f3bc7e5f05dafb345250674f3c37fe48e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 22:56:56 +0300 Subject: [PATCH 194/216] Fmt and cleanup some "if"s in protocols --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 3 ++- lib/subghz/protocols/alutech_at_4n.c | 6 ++---- lib/subghz/protocols/kinggates_stylo_4k.c | 4 +--- lib/subghz/protocols/somfy_keytis.c | 6 ++---- lib/subghz/protocols/somfy_telis.c | 6 ++---- lib/subghz/protocols/star_line.c | 6 ++---- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5ad12b509..7dead8d4e 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -29,7 +29,8 @@ static void subghz_scene_receiver_update_statusbar(void* context) { FuriString* frequency_str = furi_string_alloc(); FuriString* modulation_str = furi_string_alloc(); - subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation( + subghz->txrx, frequency_str, modulation_str, false); subghz_view_receiver_add_data_statusbar( subghz->subghz_receiver, diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 20dae49c1..47cf37d6b 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -429,10 +429,8 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( if((custom_btn_id == 0) && (original_btn_num != 0)) { btn = original_btn_num; } - //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 - } else { + // Gen new key + if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { return false; } diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index a9127d2b1..c5d21bcb0 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -197,9 +197,7 @@ static bool subghz_protocol_encoder_kinggates_stylo_4k_get_upload( furi_assert(instance); // Gen new key - if(subghz_protocol_kinggates_stylo_4k_gen_data(instance, btn)) { - //ToDo if you need to add a callback to automatically update the data on the display - } else { + if(!subghz_protocol_kinggates_stylo_4k_gen_data(instance, btn)) { return false; } diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index dd860a61d..4074d757b 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -208,10 +208,8 @@ static bool subghz_protocol_encoder_somfy_keytis_get_upload( uint8_t btn) { furi_assert(instance); - //gen new key - if(subghz_protocol_somfy_keytis_gen_data(instance, btn)) { - //ToDo if you need to add a callback to automatically update the data on the display - } else { + // Gen new key + if(!subghz_protocol_somfy_keytis_gen_data(instance, btn)) { return false; } diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 047efb688..57c6c510b 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -254,10 +254,8 @@ static bool subghz_protocol_encoder_somfy_telis_get_upload( uint8_t btn) { furi_assert(instance); - //gen new key - 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 { + // Gen new key + if(!subghz_protocol_somfy_telis_gen_data(instance, btn, false)) { return false; } diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 181dee643..cb9b26760 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -237,10 +237,8 @@ static bool subghz_protocol_encoder_star_line_get_upload( uint8_t btn) { furi_assert(instance); - //gen new key - if(subghz_protocol_star_line_gen_data(instance, btn)) { - //ToDo if you need to add a callback to automatically update the data on the display - } else { + // Gen new key + if(!subghz_protocol_star_line_gen_data(instance, btn)) { return false; } From 3e3538b9bc52bbf9337e5adc3f640cb602807b26 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 23:07:06 +0300 Subject: [PATCH 195/216] Always free --- applications/main/subghz/subghz.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 975ec540a..4f4393efb 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -355,9 +355,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { furi_record_close(RECORD_GUI); subghz->gui = NULL; - if(!alloc_for_tx_only) { - subghz_last_settings_free(subghz->last_settings); //TODO always allocated - } + subghz_last_settings_free(subghz->last_settings); // threshold rssi subghz_threshold_rssi_free(subghz->threshold_rssi); From a941ed8c2aba434d3af852fc2e7178dd70f1e9f5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 23:12:50 +0300 Subject: [PATCH 196/216] Rename funcs --- .../subghz/helpers/subghz_txrx_create_protocol_key.c | 10 +++++----- .../subghz/helpers/subghz_txrx_create_protocol_key.h | 10 +++++----- .../main/subghz/scenes/subghz_scene_set_seed.c | 6 +++--- .../main/subghz/scenes/subghz_scene_set_type.c | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 7a0060f16..053f472aa 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -116,7 +116,7 @@ bool subghz_txrx_gen_keeloq_protocol( //TODO lead to a general appearance return res; } -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename & lead to a general appearance void* context, const char* preset_name, uint32_t frequency, @@ -161,7 +161,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename & lead to return res; } -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename & lead to a general appearance void* context, const char* preset_name, uint32_t frequency, @@ -193,7 +193,7 @@ bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename & lead to a return res; } -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_faac_slh_protocol( //TODO rename & lead to a general appearance void* context, const char* preset_name, uint32_t frequency, @@ -236,7 +236,7 @@ bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename & lead to a return res; } -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename & lead to a general appearance void* context, const char* preset_name, uint32_t frequency, @@ -266,7 +266,7 @@ bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename & lead return res; } -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_somfy_telis_protocol( //TODO rename & lead to a general appearance void* context, const char* preset_name, uint32_t frequency, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 96e592936..61dbf9e56 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -63,7 +63,7 @@ bool subghz_txrx_gen_keeloq_protocol( uint16_t cnt, const char* manufacture_name); -bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename +bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename void* context, const char* preset_name, uint32_t frequency, @@ -73,7 +73,7 @@ bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename uint32_t seed, const char* manufacture_name); -bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename +bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename void* context, const char* preset_name, uint32_t frequency, @@ -82,7 +82,7 @@ bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename uint16_t cnt, bool nice_one); -bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename +bool subghz_txrx_gen_faac_slh_protocol( //TODO rename void* context, const char* preset_name, uint32_t frequency, @@ -92,7 +92,7 @@ bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename uint32_t seed, const char* manufacture_name); -bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename +bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename void* context, const char* preset_name, uint32_t frequency, @@ -100,7 +100,7 @@ bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename uint8_t btn, uint16_t cnt); -bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename +bool subghz_txrx_gen_somfy_telis_protocol( //TODO rename void* context, const char* preset_name, uint32_t frequency, diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 18bc787bb..e6850d1e3 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -45,7 +45,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 | subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( + generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( subghz->txrx, "AM650", 433920000, @@ -74,7 +74,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; if(state == SubmenuIndexFaacSLH_433) { - generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( + generated_protocol = subghz_txrx_gen_faac_slh_protocol( subghz->txrx, "AM650", 433920000, @@ -84,7 +84,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { seed, "FAAC_SLH"); } else if(state == SubmenuIndexFaacSLH_868) { - generated_protocol = subghz_scene_set_type_submenu_gen_data_faac_slh( + generated_protocol = subghz_txrx_gen_faac_slh_protocol( subghz->txrx, "AM650", 868350000, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 342f01536..23ecbb539 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -535,7 +535,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexBFTMitto: - generated_protocol = subghz_scene_set_type_submenu_gen_data_keeloq_bft( + generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( subghz->txrx, "AM650", 433920000, @@ -551,7 +551,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexAlutechAT4N: - generated_protocol = subghz_scene_set_type_submenu_gen_data_alutech_at_4n( + generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( subghz->txrx, "AM650", 433920000, (key & 0x000FFFFF) | 0x00100000, 0x44, 0x0003); if(!generated_protocol) { furi_string_set( @@ -560,7 +560,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexSomfyTelis: - generated_protocol = subghz_scene_set_type_submenu_gen_data_somfy_telis( + generated_protocol = subghz_txrx_gen_somfy_telis_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003); if(!generated_protocol) { //TODO does not use databases furi_string_set( @@ -587,7 +587,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexNiceFlorS_433_92: - generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, false); if(!generated_protocol) { furi_string_set( @@ -596,7 +596,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexNiceOne_433_92: - generated_protocol = subghz_scene_set_type_submenu_gen_data_nice_flor( + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, "AM650", 433920000, key & 0x0FFFFFFF, 0x1, 0x0003, true); if(!generated_protocol) { furi_string_set( From e7707b31f0a503ada1ae6f92d5a8c6735405da50 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 23:28:09 +0300 Subject: [PATCH 197/216] Do some TODOs --- .../subghz/scenes/subghz_scene_decode_raw.c | 21 +------------------ .../subghz/scenes/subghz_scene_read_raw.c | 4 +--- .../scenes/subghz_scene_receiver_info.c | 4 ++-- .../subghz/scenes/subghz_scene_set_type.c | 5 ----- .../subghz/scenes/subghz_scene_transmitter.c | 2 -- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 7dead8d4e..4412676f3 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -7,21 +7,6 @@ #define TAG "SubGhzDecodeRaw" #define SAMPLES_TO_READ_PER_TICK 400 -// TODO: -// [X] Remember RAW file after decoding -// [X] Decode in tick events instead of on_enter -// [X] Make "Config" label optional in subghz_view_receiver_draw (../views/receiver.c) -// [X] Make "Scanning..." label optional in subghz_view_receiver_draw (../views/receiver.c) -// [X] Add Decoding logo -// [ ] Design nicer Decoding logo -// [X] Check progress in stream_buffer, instead of raw stream -// [X] Blink led while decoding -// [X] Stop rx blink (blue, fast) on history item view -// [X] Don't reparse file on back -// [X] Fix: RX animation+LED returning from decoded detail view -// [X] Find good value for SAMPLES_TO_READ_PER_TICK -// [X] Fix: read errors (slow flash) after aborting decode read - static void subghz_scene_receiver_update_statusbar(void* context) { SubGhz* subghz = context; FuriString* history_stat_str = furi_string_alloc(); @@ -163,7 +148,7 @@ void subghz_scene_decode_raw_on_enter(void* context) { FuriString* item_time = furi_string_alloc(); subghz_view_receiver_set_lock( - subghz->subghz_receiver, subghz_is_locked(subghz)); //TODO Doesn't matter in DecodeRAW + subghz->subghz_receiver, false); //TODO Doesn't matter in DecodeRAW subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz); @@ -243,10 +228,6 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) { notification_message(subghz->notifications, &sequence_display_backlight_off); consumed = true; break; - case SubGhzCustomEventViewReceiverUnlock: - subghz_unlock(subghz); //TODO There is no such event in DecodeRAW - consumed = true; - break; default: break; } diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 4b8303ddd..a1b25cbd1 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -42,10 +42,8 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { #ifdef SUBGHZ_EXT_PRESET_NAME subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, true); - //TODO if need subghz_txrx_get_preset - //furi_string_printf(modulation_str, "%s", furi_string_get_cstr(subghz->txrx->preset->name)); #else - subghz_get_frequency_modulation(subghz->txrx, frequency_str, modulation_str, false); + subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str, false); #endif subghz_read_raw_add_data_statusbar( subghz->subghz_read_raw, diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index c04f39cb8..370638931 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -27,7 +27,7 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { if(subghz_txrx_load_decoder_by_name_protocol( subghz->txrx, subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) { - //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal + //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this signal subghz_protocol_decoder_base_deserialize( subghz_txrx_get_decoder(subghz->txrx), subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen)); @@ -140,7 +140,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) widget_reset(subghz->widget); subghz_scene_receiver_info_draw_widget(subghz); - subghz_txrx_stop(subghz->txrx); //TODO this is probably a redundant call + subghz_txrx_stop(subghz->txrx); if(!subghz->in_decoder_scene) { subghz_txrx_rx_start(subghz->txrx); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 23ecbb539..ef53006da 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -562,11 +562,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexSomfyTelis: generated_protocol = subghz_txrx_gen_somfy_telis_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003); - if(!generated_protocol) { //TODO does not use databases - 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: generated_protocol = subghz_txrx_gen_keeloq_protocol( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index c3ae04a8f..dc8c51b7a 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -81,8 +81,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! - subghz_txrx_stop(subghz->txrx); //TODO this is probably a redundant call - if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { scene_manager_next_scene( subghz->scene_manager, SubGhzSceneShowOnlyRx); //TODO Is this necessary? From b38a593c4fcc2dd4bc4234111c404eb1c4a5bcfe Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 23:36:52 +0300 Subject: [PATCH 198/216] Remove this --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 4412676f3..54c729cc3 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -147,8 +147,6 @@ void subghz_scene_decode_raw_on_enter(void* context) { FuriString* item_name = furi_string_alloc(); FuriString* item_time = furi_string_alloc(); - subghz_view_receiver_set_lock( - subghz->subghz_receiver, false); //TODO Doesn't matter in DecodeRAW subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz); From 3531caaa0b80844cbb541afce821af62d783b3d2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 10 May 2023 23:48:47 +0300 Subject: [PATCH 199/216] Clean up some comments, rename is done --- .../subghz/helpers/subghz_txrx_create_protocol_key.c | 10 +++++----- .../subghz/helpers/subghz_txrx_create_protocol_key.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 053f472aa..0631c7c15 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -116,7 +116,7 @@ bool subghz_txrx_gen_keeloq_protocol( //TODO lead to a general appearance return res; } -bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_keeloq_bft_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -161,7 +161,7 @@ bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename & lead to a general appe return res; } -bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_nice_flor_s_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -193,7 +193,7 @@ bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename & lead to a general app return res; } -bool subghz_txrx_gen_faac_slh_protocol( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_faac_slh_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -236,7 +236,7 @@ bool subghz_txrx_gen_faac_slh_protocol( //TODO rename & lead to a general appear return res; } -bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_alutech_at_4n_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -266,7 +266,7 @@ bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename & lead to a general a return res; } -bool subghz_txrx_gen_somfy_telis_protocol( //TODO rename & lead to a general appearance +bool subghz_txrx_gen_somfy_telis_protocol( void* context, const char* preset_name, uint32_t frequency, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 61dbf9e56..a5fa2a802 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -63,7 +63,7 @@ bool subghz_txrx_gen_keeloq_protocol( uint16_t cnt, const char* manufacture_name); -bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename +bool subghz_txrx_gen_keeloq_bft_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -73,7 +73,7 @@ bool subghz_txrx_gen_keeloq_bft_protocol( //TODO rename uint32_t seed, const char* manufacture_name); -bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename +bool subghz_txrx_gen_nice_flor_s_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -82,7 +82,7 @@ bool subghz_txrx_gen_nice_flor_s_protocol( //TODO rename uint16_t cnt, bool nice_one); -bool subghz_txrx_gen_faac_slh_protocol( //TODO rename +bool subghz_txrx_gen_faac_slh_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -92,7 +92,7 @@ bool subghz_txrx_gen_faac_slh_protocol( //TODO rename uint32_t seed, const char* manufacture_name); -bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename +bool subghz_txrx_gen_alutech_at_4n_protocol( void* context, const char* preset_name, uint32_t frequency, @@ -100,7 +100,7 @@ bool subghz_txrx_gen_alutech_at_4n_protocol( //TODO rename uint8_t btn, uint16_t cnt); -bool subghz_txrx_gen_somfy_telis_protocol( //TODO rename +bool subghz_txrx_gen_somfy_telis_protocol( void* context, const char* preset_name, uint32_t frequency, From bc93de0f03856e6950834ba47157bba9e161cc62 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 00:01:28 +0300 Subject: [PATCH 200/216] remove unnecessary scene switch --- applications/main/subghz/scenes/subghz_scene_transmitter.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index dc8c51b7a..b07785c06 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -81,11 +81,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! - if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { - scene_manager_next_scene( - subghz->scene_manager, SubGhzSceneShowOnlyRx); //TODO Is this necessary? - } - + subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); subghz_txrx_stop(subghz->txrx); furi_hal_subghz_set_rolling_counter_mult(tmp_counter); } From d91f70b8378be56e0a3e91a0aa4e6b84068bd34b Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 10 May 2023 23:36:03 +0100 Subject: [PATCH 201/216] Move config file migration to flipper init --- .../main/archive/helpers/archive_favorites.c | 7 --- applications/main/u2f/u2f_app.c | 5 --- applications/services/bt/bt_service/bt.c | 4 -- applications/services/bt/bt_settings.c | 19 +------- applications/services/bt/bt_settings.h | 3 ++ .../services/desktop/desktop_settings.c | 17 +------ .../services/dolphin/helpers/dolphin_state.c | 15 ------- .../services/dolphin/helpers/dolphin_state.h | 3 ++ .../services/notification/notification_app.c | 17 +------ applications/services/power/power_settings.c | 13 +----- furi/flipper.c | 44 +++++++++++++++++++ 11 files changed, 54 insertions(+), 93 deletions(-) diff --git a/applications/main/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c index 9d4b963f5..9f3039041 100644 --- a/applications/main/archive/helpers/archive_favorites.c +++ b/applications/main/archive/helpers/archive_favorites.c @@ -140,13 +140,6 @@ bool archive_favorites_read(void* context) { bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - if(!result) { - storage_file_close(file); - storage_common_copy(storage, ARCHIVE_FAV_OLD_PATH, ARCHIVE_FAV_PATH); - storage_common_remove(storage, ARCHIVE_FAV_OLD_PATH); - result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - } - if(result) { while(1) { if(!archive_favorites_read_line(file, buffer)) { diff --git a/applications/main/u2f/u2f_app.c b/applications/main/u2f/u2f_app.c index fb9b4241c..db94a398c 100644 --- a/applications/main/u2f/u2f_app.c +++ b/applications/main/u2f/u2f_app.c @@ -28,11 +28,6 @@ U2fApp* u2f_app_alloc() { app->gui = furi_record_open(RECORD_GUI); app->notifications = furi_record_open(RECORD_NOTIFICATION); - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_rename(storage, U2F_CNT_OLD_FILE, U2F_CNT_FILE); - storage_common_copy(storage, U2F_KEY_OLD_FILE, U2F_KEY_FILE); - furi_record_close(RECORD_STORAGE); - app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&u2f_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index b4a6b25a4..1781d03d7 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -126,10 +126,6 @@ Bt* bt_alloc() { bt_settings_save(&bt->bt_settings); } // Keys storage - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, BT_KEYS_STORAGE_OLD_PATH, BT_KEYS_STORAGE_PATH); - storage_common_remove(storage, BT_KEYS_STORAGE_OLD_PATH); - furi_record_close(RECORD_STORAGE); bt->keys_storage = bt_keys_storage_alloc(BT_KEYS_STORAGE_PATH); // Alloc queue bt->message_queue = furi_message_queue_alloc(8, sizeof(BtMessage)); diff --git a/applications/services/bt/bt_settings.c b/applications/services/bt/bt_settings.c index 92e6c7d5d..6a6c5f562 100644 --- a/applications/services/bt/bt_settings.c +++ b/applications/services/bt/bt_settings.c @@ -4,31 +4,14 @@ #include #include -#define BT_SETTINGS_OLD_PATH INT_PATH(".bt.settings") -#define BT_SETTINGS_PATH CFG_PATH("bt.settings") #define BT_SETTINGS_VERSION (0) #define BT_SETTINGS_MAGIC (0x19) bool bt_settings_load(BtSettings* bt_settings) { furi_assert(bt_settings); - bool ret = saved_struct_load( + return saved_struct_load( BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); - - if(!ret) { - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, BT_SETTINGS_OLD_PATH, BT_SETTINGS_PATH); - storage_common_remove(storage, BT_SETTINGS_OLD_PATH); - furi_record_close(RECORD_STORAGE); - ret = saved_struct_load( - BT_SETTINGS_PATH, - bt_settings, - sizeof(BtSettings), - BT_SETTINGS_MAGIC, - BT_SETTINGS_VERSION); - } - - return ret; } bool bt_settings_save(BtSettings* bt_settings) { diff --git a/applications/services/bt/bt_settings.h b/applications/services/bt/bt_settings.h index 620a3f5a6..cd6be60c4 100644 --- a/applications/services/bt/bt_settings.h +++ b/applications/services/bt/bt_settings.h @@ -7,6 +7,9 @@ extern "C" { #endif +#define BT_SETTINGS_OLD_PATH INT_PATH(".bt.settings") +#define BT_SETTINGS_PATH CFG_PATH("bt.settings") + typedef struct { bool enabled; } BtSettings; diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index 9c95e950f..d1df4a9a6 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -10,25 +10,10 @@ bool DESKTOP_SETTINGS_SAVE(DesktopSettings* x) { } bool DESKTOP_SETTINGS_LOAD(DesktopSettings* x) { - bool ret = saved_struct_load( + return saved_struct_load( DESKTOP_SETTINGS_PATH, x, sizeof(DesktopSettings), DESKTOP_SETTINGS_MAGIC, DESKTOP_SETTINGS_VER); - - if(!ret) { - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, DESKTOP_SETTINGS_OLD_PATH, DESKTOP_SETTINGS_PATH); - storage_common_remove(storage, DESKTOP_SETTINGS_OLD_PATH); - furi_record_close(RECORD_STORAGE); - ret = saved_struct_load( - DESKTOP_SETTINGS_PATH, - x, - sizeof(DesktopSettings), - DESKTOP_SETTINGS_MAGIC, - DESKTOP_SETTINGS_VER); - } - - return ret; } diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index fba3c5a90..1a418ead2 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -10,8 +10,6 @@ #define TAG "DolphinState" -#define DOLPHIN_STATE_OLD_PATH INT_PATH(".dolphin.state") -#define DOLPHIN_STATE_PATH CFG_PATH("dolphin.state") #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 #define DOLPHIN_STATE_HEADER_VERSION 0x01 @@ -61,19 +59,6 @@ bool dolphin_state_load(DolphinState* dolphin_state) { DOLPHIN_STATE_HEADER_MAGIC, DOLPHIN_STATE_HEADER_VERSION); - if(!success) { - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, DOLPHIN_STATE_OLD_PATH, DOLPHIN_STATE_PATH); - storage_common_remove(storage, DOLPHIN_STATE_OLD_PATH); - furi_record_close(RECORD_STORAGE); - success = saved_struct_load( - DOLPHIN_STATE_PATH, - &dolphin_state->data, - sizeof(DolphinStoreData), - DOLPHIN_STATE_HEADER_MAGIC, - DOLPHIN_STATE_HEADER_VERSION); - } - if(success) { if((dolphin_state->data.butthurt > BUTTHURT_MAX) || (dolphin_state->data.butthurt < BUTTHURT_MIN)) { diff --git a/applications/services/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h index 65cea35ac..e869775f7 100644 --- a/applications/services/dolphin/helpers/dolphin_state.h +++ b/applications/services/dolphin/helpers/dolphin_state.h @@ -9,6 +9,9 @@ extern "C" { #endif +#define DOLPHIN_STATE_OLD_PATH INT_PATH(".dolphin.state") +#define DOLPHIN_STATE_PATH CFG_PATH("dolphin.state") + #define DOLPHIN_LEVEL_COUNT 29 typedef struct DolphinState DolphinState; diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 61be402bd..409c51957 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -421,27 +421,12 @@ static bool notification_save_settings(NotificationApp* app) { } static bool notification_load_settings(NotificationApp* app) { - bool ret = saved_struct_load( + return saved_struct_load( NOTIFICATION_SETTINGS_PATH, &app->settings, sizeof(NotificationSettings), NOTIFICATION_SETTINGS_MAGIC, NOTIFICATION_SETTINGS_VERSION); - - if(!ret) { - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, NOTIFICATION_SETTINGS_OLD_PATH, NOTIFICATION_SETTINGS_PATH); - storage_common_remove(storage, NOTIFICATION_SETTINGS_OLD_PATH); - furi_record_close(RECORD_STORAGE); - ret = saved_struct_load( - NOTIFICATION_SETTINGS_PATH, - &app->settings, - sizeof(NotificationSettings), - NOTIFICATION_SETTINGS_MAGIC, - NOTIFICATION_SETTINGS_VERSION); - } - - return ret; } static void input_event_callback(const void* value, void* context) { diff --git a/applications/services/power/power_settings.c b/applications/services/power/power_settings.c index cd456a5a8..b98c382c0 100644 --- a/applications/services/power/power_settings.c +++ b/applications/services/power/power_settings.c @@ -6,17 +6,6 @@ bool SAVE_POWER_SETTINGS(uint32_t* x) { } bool LOAD_POWER_SETTINGS(uint32_t* x) { - bool ret = saved_struct_load( + return saved_struct_load( POWER_SETTINGS_PATH, x, sizeof(uint32_t), POWER_SETTINGS_MAGIC, POWER_SETTINGS_VER); - - if(!ret) { - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_copy(storage, POWER_SETTINGS_OLD_PATH, POWER_SETTINGS_PATH); - storage_common_remove(storage, POWER_SETTINGS_OLD_PATH); - furi_record_close(RECORD_STORAGE); - ret = saved_struct_load( - POWER_SETTINGS_PATH, x, sizeof(uint32_t), POWER_SETTINGS_MAGIC, POWER_SETTINGS_VER); - } - - return ret; } diff --git a/furi/flipper.c b/furi/flipper.c index d2b4f9047..a788dfc74 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -4,6 +4,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #define TAG "Flipper" @@ -28,6 +37,39 @@ static void flipper_print_version(const char* target, const Version* version) { } } +void flipper_migrate_files() { + if(!furi_hal_is_normal_boot()) return; + Storage* storage = furi_record_open(RECORD_STORAGE); + + // Revert cringe + storage_common_remove(storage, INT_PATH(".passport.settings")); + + // Migrate files + storage_common_copy(storage, ARCHIVE_FAV_OLD_PATH, ARCHIVE_FAV_PATH); + storage_common_remove(storage, ARCHIVE_FAV_OLD_PATH); + storage_common_copy(storage, BT_SETTINGS_OLD_PATH, BT_SETTINGS_PATH); + storage_common_remove(storage, BT_SETTINGS_OLD_PATH); + storage_common_copy(storage, DOLPHIN_STATE_OLD_PATH, DOLPHIN_STATE_PATH); + storage_common_remove(storage, DOLPHIN_STATE_OLD_PATH); + storage_common_copy(storage, POWER_SETTINGS_OLD_PATH, POWER_SETTINGS_PATH); + storage_common_remove(storage, POWER_SETTINGS_OLD_PATH); + storage_common_copy(storage, BT_KEYS_STORAGE_OLD_PATH, BT_KEYS_STORAGE_PATH); + storage_common_remove(storage, BT_KEYS_STORAGE_OLD_PATH); + storage_common_copy(storage, DESKTOP_SETTINGS_OLD_PATH, DESKTOP_SETTINGS_PATH); + storage_common_remove(storage, DESKTOP_SETTINGS_OLD_PATH); + storage_common_copy(storage, NOTIFICATION_SETTINGS_OLD_PATH, NOTIFICATION_SETTINGS_PATH); + storage_common_remove(storage, NOTIFICATION_SETTINGS_OLD_PATH); + + // Special care for U2F + if(storage_common_exists(storage, U2F_CNT_OLD_FILE)) { // Is on Int + storage_common_remove(storage, U2F_CNT_FILE); // Remove outdated on Ext + storage_common_rename(storage, U2F_CNT_OLD_FILE, U2F_CNT_FILE); // Int -> Ext + } + storage_common_copy(storage, U2F_KEY_OLD_FILE, U2F_KEY_FILE); // Ext -> Int + + furi_record_close(RECORD_STORAGE); +} + void flipper_start_service(const FlipperApplication* service) { FURI_LOG_D(TAG, "Starting service %s", service->name); @@ -47,6 +89,8 @@ void flipper_init() { // Start storage service first, thanks OFW :/ flipper_start_service(&FLIPPER_SERVICES[0]); + flipper_migrate_files(); + NAMESPOOF_INIT(); XTREME_SETTINGS_LOAD(); XTREME_ASSETS_LOAD(); From 09ff6da5ea282bc75d5aaa58f12c219832856376 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 11 May 2023 00:26:11 +0100 Subject: [PATCH 202/216] Remove subghz region --- .../scenes/xtreme_app_scene_protocols.c | 13 -- applications/main/xtreme_app/xtreme_app.c | 4 +- applications/main/xtreme_app/xtreme_app.h | 1 - .../desktop/views/desktop_view_debug.c | 3 +- applications/settings/about/about.c | 3 +- firmware/targets/f7/api_symbols.csv | 5 +- .../targets/f7/furi_hal/furi_hal_region.c | 119 +++--------------- .../targets/f7/furi_hal/furi_hal_subghz.c | 70 ++--------- .../targets/f7/furi_hal/furi_hal_subghz.h | 10 +- .../f7/furi_hal/furi_hal_subghz_configs.h | 10 -- .../furi_hal_include/furi_hal_region.h | 3 - furi/flipper.c | 1 + 12 files changed, 40 insertions(+), 202 deletions(-) diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_protocols.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_protocols.c index d8244d30d..28b97618e 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_protocols.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_protocols.c @@ -5,7 +5,6 @@ enum VarItemListIndex { VarItemListIndexBadbtRemember, VarItemListIndexSubghzFrequencies, VarItemListIndexSubghzExtend, - VarItemListIndexSubghzBypass, }; void xtreme_app_scene_protocols_var_item_list_callback(void* context, uint32_t index) { @@ -36,13 +35,6 @@ static void xtreme_app_scene_protocols_subghz_extend_changed(VariableItem* item) app->save_subghz = true; } -static void xtreme_app_scene_protocols_subghz_bypass_changed(VariableItem* item) { - XtremeApp* app = variable_item_get_context(item); - app->subghz_bypass = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); - app->save_subghz = true; -} - void xtreme_app_scene_protocols_on_enter(void* context) { XtremeApp* app = context; XtremeSettings* xtreme_settings = XTREME_SETTINGS(); @@ -66,11 +58,6 @@ void xtreme_app_scene_protocols_on_enter(void* context) { variable_item_set_current_value_index(item, app->subghz_extend); variable_item_set_current_value_text(item, app->subghz_extend ? "ON" : "OFF"); - item = variable_item_list_add( - var_item_list, "SubGHz Bypass", 2, xtreme_app_scene_protocols_subghz_bypass_changed, app); - variable_item_set_current_value_index(item, app->subghz_bypass); - variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); - variable_item_list_set_enter_callback( var_item_list, xtreme_app_scene_protocols_var_item_list_callback, app); diff --git a/applications/main/xtreme_app/xtreme_app.c b/applications/main/xtreme_app/xtreme_app.c index e86db4fc5..623bbcdc9 100644 --- a/applications/main/xtreme_app/xtreme_app.c +++ b/applications/main/xtreme_app/xtreme_app.c @@ -64,7 +64,7 @@ bool xtreme_app_apply(XtremeApp* app) { } if(app->save_subghz) { - furi_hal_subghz_set_extend_settings(app->subghz_extend, app->subghz_bypass); + furi_hal_subghz_set_is_extended(app->subghz_extend); } if(app->save_name) { @@ -247,7 +247,7 @@ XtremeApp* xtreme_app_alloc() { flipper_format_free(file); furi_record_close(RECORD_STORAGE); - furi_hal_subghz_get_extend_settings(&app->subghz_extend, &app->subghz_bypass); + app->subghz_extend = furi_hal_subghz_get_is_extended(); strlcpy(app->device_name, furi_hal_version_get_name_ptr(), FURI_HAL_VERSION_ARRAY_NAME_LENGTH); diff --git a/applications/main/xtreme_app/xtreme_app.h b/applications/main/xtreme_app/xtreme_app.h index 542353338..dedb9630c 100644 --- a/applications/main/xtreme_app/xtreme_app.h +++ b/applications/main/xtreme_app/xtreme_app.h @@ -51,7 +51,6 @@ typedef struct { uint8_t subghz_hopper_index; char subghz_freq_buffer[XTREME_SUBGHZ_FREQ_BUFFER_SIZE]; bool subghz_extend; - bool subghz_bypass; char device_name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; int32_t xp_level; FuriString* version_tag; diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index 934c8c7ee..2b820e64e 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -37,13 +37,12 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%d.F%dB%dC%d %s:%s %s", + "%d.F%dB%dC%d %s %s", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 168f1094b..2d38d930a 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -99,13 +99,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* furi_string_cat_printf( buffer, - "%d.F%dB%dC%d %s:%s %s\n", + "%d.F%dB%dC%d %s %s\n", furi_hal_version_get_hw_version(), furi_hal_version_get_hw_target(), furi_hal_version_get_hw_body(), furi_hal_version_get_hw_connect(), furi_hal_version_get_hw_region_name_otp(), - furi_hal_region_get_name(), my_name ? my_name : "Unknown"); furi_string_cat_printf(buffer, "Serial Number:\n"); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 22b419d7b..6a1b21773 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1361,7 +1361,6 @@ Function,+,furi_hal_random_get,uint32_t, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, -Function,+,furi_hal_region_init,void, Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t Function,+,furi_hal_region_is_provisioned,_Bool, Function,+,furi_hal_region_set,void,FuriHalRegion* @@ -1453,8 +1452,8 @@ Function,-,furi_hal_subghz_dump_state,void, Function,+,furi_hal_subghz_enable_ext_power,_Bool, Function,+,furi_hal_subghz_flush_rx,void, Function,+,furi_hal_subghz_flush_tx,void, -Function,+,furi_hal_subghz_get_extend_settings,void,"_Bool*, _Bool*" Function,+,furi_hal_subghz_get_external_power_disable,_Bool, +Function,+,furi_hal_subghz_get_is_extended,_Bool, 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, @@ -1478,10 +1477,10 @@ Function,+,furi_hal_subghz_rx,void, Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, Function,+,furi_hal_subghz_select_radio_type,void,SubGhzRadioType Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* -Function,+,furi_hal_subghz_set_extend_settings,void,"_Bool, _Bool" Function,+,furi_hal_subghz_set_external_power_disable,void,_Bool 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_is_extended,void,_Bool Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t Function,+,furi_hal_subghz_set_timestamp_file_names,void,_Bool diff --git a/firmware/targets/f7/furi_hal/furi_hal_region.c b/firmware/targets/f7/furi_hal/furi_hal_region.c index 191ca3873..0f0cb855c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_region.c +++ b/firmware/targets/f7/furi_hal/furi_hal_region.c @@ -1,6 +1,5 @@ #include -#include -#include +#include const FuriHalRegion furi_hal_region_zero = { .country_code = "00", @@ -14,115 +13,18 @@ const FuriHalRegion furi_hal_region_zero = { }, }}; -const FuriHalRegion furi_hal_region_eu_ru = { - .country_code = "EU", - .bands_count = 2, - .bands = { - { - .start = 433050000, - .end = 434790000, - .power_limit = 12, - .duty_cycle = 50, - }, - { - .start = 868150000, - .end = 868550000, - .power_limit = 12, - .duty_cycle = 50, - }}}; - -const FuriHalRegion furi_hal_region_us_ca_au = { - .country_code = "US", - .bands_count = 3, - .bands = { - { - .start = 304100000, - .end = 321950000, - .power_limit = 12, - .duty_cycle = 50, - }, - { - .start = 433050000, - .end = 434790000, - .power_limit = 12, - .duty_cycle = 50, - }, - { - .start = 915000000, - .end = 928000000, - .power_limit = 12, - .duty_cycle = 50, - }}}; - -const FuriHalRegion furi_hal_region_jp = { - .country_code = "JP", - .bands_count = 2, - .bands = { - { - .start = 312000000, - .end = 315250000, - .power_limit = 12, - .duty_cycle = 50, - }, - { - .start = 920500000, - .end = 923500000, - .power_limit = 12, - .duty_cycle = 50, - }}}; - static const FuriHalRegion* furi_hal_region = NULL; -void furi_hal_region_init() { - FuriHalVersionRegion region = furi_hal_version_get_hw_region(); - - if(region == FuriHalVersionRegionUnknown) { - furi_hal_region = &furi_hal_region_zero; - } else if(region == FuriHalVersionRegionEuRu) { - furi_hal_region = &furi_hal_region_eu_ru; - } else if(region == FuriHalVersionRegionUsCaAu) { - furi_hal_region = &furi_hal_region_us_ca_au; - } else if(region == FuriHalVersionRegionJp) { - furi_hal_region = &furi_hal_region_jp; - } -} - const FuriHalRegion* furi_hal_region_get() { - return furi_hal_region; + return &furi_hal_region_zero; } void furi_hal_region_set(FuriHalRegion* region) { - furi_hal_region = region; -} - -bool furi_hal_region_is_provisioned() { - return furi_hal_region != NULL; -} - -const char* furi_hal_region_get_name() { - if(furi_hal_region) { - return furi_hal_region->country_code; - } else { - return "--"; - } -} - -bool furi_hal_region_is_frequency_allowed(uint32_t frequency) { - bool isAllowed = true; - if(!furi_hal_region) { - isAllowed = false; - } - const FuriHalRegionBand* band = furi_hal_region_get_band(frequency); - if(!band) { - isAllowed = false; - } - if(!isAllowed) { - isAllowed = furi_hal_subghz_is_tx_allowed(frequency); - } - return isAllowed; + UNUSED(region); } const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency) { + furi_hal_region = &furi_hal_region_zero; if(!furi_hal_region) { return NULL; } @@ -136,3 +38,16 @@ const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency) { return NULL; } + +bool furi_hal_region_is_frequency_allowed(uint32_t frequency) { + UNUSED(frequency); + return true; +} + +bool furi_hal_region_is_provisioned() { + return true; +} + +const char* furi_hal_region_get_name() { + return "00"; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 573c5b8ab..a7261cc42 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -1,6 +1,6 @@ #include #include -#include + #include #include #include @@ -448,22 +448,21 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { return value; } -void furi_hal_subghz_get_extend_settings(bool* extend, bool* bypass) { - *extend = false; - *bypass = false; +bool furi_hal_subghz_get_is_extended() { + bool is_extended = false; Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) { - flipper_format_read_bool(file, "use_ext_range_at_own_risk", extend, 1); - flipper_format_read_bool(file, "ignore_default_tx_region", bypass, 1); + flipper_format_read_bool(file, "use_ext_range_at_own_risk", &is_extended, 1); } flipper_format_free(file); furi_record_close(RECORD_STORAGE); + return is_extended; } -void furi_hal_subghz_set_extend_settings(bool extend, bool bypass) { +void furi_hal_subghz_set_is_extended(bool is_extended) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); @@ -473,11 +472,7 @@ void furi_hal_subghz_set_extend_settings(bool extend, bool bypass) { if(!flipper_format_write_comment_cstr( file, "Whether to allow extended ranges that can break your flipper")) break; - if(!flipper_format_write_bool(file, "use_ext_range_at_own_risk", &extend, 1)) break; - if(!flipper_format_write_comment_cstr( - file, "Whether to ignore the default TX region settings")) - break; - if(!flipper_format_write_bool(file, "ignore_default_tx_region", &bypass, 1)) break; + if(!flipper_format_write_bool(file, "use_ext_range_at_own_risk", &is_extended, 1)) break; } while(0); flipper_format_free(file); @@ -485,63 +480,22 @@ void furi_hal_subghz_set_extend_settings(bool extend, bool bypass) { } bool furi_hal_subghz_is_tx_allowed(uint32_t value) { - bool is_extended; - bool is_allowed; - furi_hal_subghz_get_extend_settings(&is_extended, &is_allowed); + bool is_extended = furi_hal_subghz_get_is_extended(); - switch(furi_hal_version_get_hw_region_otp()) { - case FuriHalVersionRegionEuRu: - //433,05..434,79; 868,15..868,55 - if(!(value >= 433050000 && value <= 434790000) && - !(value >= 868150000 && value <= 868550000)) { - } else { - is_allowed = true; - } - break; - case FuriHalVersionRegionUsCaAu: - //304,10..321,95; 433,05..434,79; 915,00..928,00 - if(!(value >= 304100000 && value <= 321950000) && - !(value >= 433050000 && value <= 434790000) && - !(value >= 915000000 && value <= 928000000)) { - } else { - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - if(value <= 321950000 && - ((furi_hal_subghz.preset == FuriHalSubGhzPresetOok270Async) || - (furi_hal_subghz.preset == FuriHalSubGhzPresetOok650Async))) { - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); - } - } - is_allowed = true; - } - break; - case FuriHalVersionRegionJp: - //312,00..315,25; 920,50..923,50 - if(!(value >= 312000000 && value <= 315250000) && - !(value >= 920500000 && value <= 923500000)) { - } else { - is_allowed = true; - } - break; - - default: - is_allowed = true; - break; - } - // No flag - test original range, flag set, test extended range if(!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350 !(value >= 386999938 && value <= 467750000) && // was increased from 464 to 467.75 !(value >= 778999847 && value <= 928000000) && !(is_extended)) { - FURI_LOG_I(TAG, "Frequency blocked - outside regional range"); - is_allowed = false; + FURI_LOG_I(TAG, "Frequency blocked - outside default range"); + return false; } else if( !(value >= 281000000 && value <= 361000000) && !(value >= 378000000 && value <= 481000000) && !(value >= 749000000 && value <= 962000000) && is_extended) { FURI_LOG_I(TAG, "Frequency blocked - outside extended range"); - is_allowed = false; + return false; } - return is_allowed; + return true; } uint32_t furi_hal_subghz_set_frequency(uint32_t value) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h index a292c642f..8383c27f2 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -227,17 +227,15 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); /** Read extend and bypass settings values into out params * - * @param extend pointer to bool for extend - * @param bypass pointer to bool for bypass + * @return is_extended bool */ -void furi_hal_subghz_get_extend_settings(bool* extend, bool* bypass); +bool furi_hal_subghz_get_is_extended(); /** Set extend and bypass settings values to file * - * @param extend bool for extend - * @param bypass bool for bypass + * @param is_extended bool for extend */ -void furi_hal_subghz_set_extend_settings(bool extend, bool bypass); +void furi_hal_subghz_set_is_extended(bool is_extended); /** Сheck if transmission is allowed on this frequency with your current config * diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h b/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h index 5ea17b6dd..b2b5760fd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h @@ -273,16 +273,6 @@ static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { 0x00, 0x00}; -static const uint8_t furi_hal_subghz_preset_ook_async_patable_au[8] = { - 0x00, - 0x37, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 0x00, diff --git a/firmware/targets/furi_hal_include/furi_hal_region.h b/firmware/targets/furi_hal_include/furi_hal_region.h index ddc8a6a43..9586d51ed 100644 --- a/firmware/targets/furi_hal_include/furi_hal_region.h +++ b/firmware/targets/furi_hal_include/furi_hal_region.h @@ -21,9 +21,6 @@ typedef struct { FuriHalRegionBand bands[]; } FuriHalRegion; -/** Initialize region */ -void furi_hal_region_init(); - /** Get Region Data. * * Region data may be allocated in Flash or in RAM. diff --git a/furi/flipper.c b/furi/flipper.c index a788dfc74..4419877e9 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -43,6 +43,7 @@ void flipper_migrate_files() { // Revert cringe storage_common_remove(storage, INT_PATH(".passport.settings")); + storage_common_remove(storage, INT_PATH(".region_data")); // Migrate files storage_common_copy(storage, ARCHIVE_FAV_OLD_PATH, ARCHIVE_FAV_PATH); From 054245c980c7da2a89d87106e8f2dbcb764c582c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 02:32:53 +0300 Subject: [PATCH 203/216] Remove unneeded include --- firmware/targets/f7/furi_hal/furi_hal_idle_timer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h index 36b45755a..9f91db14e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h +++ b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h @@ -3,7 +3,6 @@ #include #include #include -#include // Timer used for tickless idle #define FURI_HAL_IDLE_TIMER_MAX 0xFFFF From c4010a6c780614f1a5faaead6caa0052ce39d57d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 02:58:28 +0300 Subject: [PATCH 204/216] Update rfid fuzzer readme --- applications/external/flipfrid/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/external/flipfrid/README.md b/applications/external/flipfrid/README.md index 69fdb3e66..83d849454 100644 --- a/applications/external/flipfrid/README.md +++ b/applications/external/flipfrid/README.md @@ -1,10 +1,10 @@ # Flipfrid -Basic EM4100 and HIDProx Fuzzer. +Basic LFRFID Fuzzer. ## Why -Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz). +Flipfrid is a simple Rfid fuzzer using lfrfid protocols (125khz). Objective is to provide a simple to use fuzzer to test readers by emulating various cards. - EM4100 cards use a 1 byte customer id and 4 bytes card id. @@ -14,12 +14,16 @@ Objective is to provide a simple to use fuzzer to test readers by emulating vari 1) Select the Protocol with the left and right arrows 2) Select the Mode with the up and down arrows +3) Set TD (Time delay) between ID switch if you need, or left it as is +4) Click Start ### Info -There are 2 Protocols: +There are 4 Protocols: - EM4100 - HIDProx +- PAC/Stanley +- H10301 There are 4 modes: - Default Values: Try factory/default keys and emulate one after the other. @@ -28,8 +32,5 @@ There are 4 modes: - Uids list: Iterate over an input text file (one uid per line) and emulate one after the other. - - TODO : -- blank screen on back press - Add second byte test to `BF customer id` From 654a622607dcade641b8825574da1744e314376c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 03:05:04 +0300 Subject: [PATCH 205/216] Move counter incr out of debug, change max value to 3 making it not that harmful if user don't understand what it does --- .../scenes/subghz_scene_ext_module_settings.c | 67 +++++++------------ 1 file changed, 23 insertions(+), 44 deletions(-) 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 963483db3..e91ebd47f 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -31,14 +31,11 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = { "17(1W)", }; -#define DEBUG_COUNTER_COUNT 6 +#define DEBUG_COUNTER_COUNT 3 const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+1", "+2", "+3", - "+4", - "+5", - "+10", }; static void subghz_scene_ext_module_changed(VariableItem* item) { @@ -80,15 +77,6 @@ static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) { 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; } @@ -157,6 +145,28 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { variable_item_set_current_value_index(item, value_index_time); variable_item_set_current_value_text(item, timestamp_names_text[value_index_time]); + item = variable_item_list_add( + subghz->variable_item_list, + "Counter incr.", + 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; + 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]); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { item = variable_item_list_add( subghz->variable_item_list, @@ -167,37 +177,6 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { value_index_dpin = subghz_txrx_get_debug_pin_state(subghz->txrx); 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 incr.", - 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); From 964424ff7e3f897f924cc305d4dc866fe1e9ea64 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 11 May 2023 01:05:52 +0100 Subject: [PATCH 206/216] Fix infrared disable otg (thanks Nano!) --- applications/main/infrared/infrared.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 0abd6c709..407b1849e 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -480,7 +480,9 @@ int32_t infrared_app(char* p) { view_dispatcher_run(infrared->view_dispatcher); - furi_hal_power_disable_otg(); + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_disable_otg(); + } infrared_free(infrared); return 0; From 957162b00605fe64a48f3d267d7f14eb54e49ceb Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 11 May 2023 01:08:40 +0100 Subject: [PATCH 207/216] Mfw otg power go brrr --- .../main/infrared/scenes/infrared_scene_debug_settings.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/main/infrared/scenes/infrared_scene_debug_settings.c b/applications/main/infrared/scenes/infrared_scene_debug_settings.c index 28ec7dfdc..bef666275 100644 --- a/applications/main/infrared/scenes/infrared_scene_debug_settings.c +++ b/applications/main/infrared/scenes/infrared_scene_debug_settings.c @@ -27,7 +27,9 @@ static void infrared_scene_debug_settings_power_changed(VariableItem* item) { furi_delay_ms(10); } } else { - furi_hal_power_disable_otg(); + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_disable_otg(); + } } variable_item_set_current_value_text(item, value ? "ON" : "OFF"); } From a1fa5224a3ea71f366bba584a7336abb25eaaf15 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 03:15:15 +0300 Subject: [PATCH 208/216] Infrared external output move out of debug and add power option --- applications/main/infrared/infrared.c | 5 ++++ .../scenes/infrared_scene_debug_settings.c | 26 +++++++++++++++++++ .../infrared/scenes/infrared_scene_start.c | 18 ++++++------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index a88306cc5..b2be5f1af 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -246,6 +246,11 @@ static void infrared_free(Infrared* infrared) { furi_string_free(infrared->file_path); + // Disable 5v power if was enabled for external module + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_disable_otg(); + } + free(infrared); } diff --git a/applications/main/infrared/scenes/infrared_scene_debug_settings.c b/applications/main/infrared/scenes/infrared_scene_debug_settings.c index 0bc830788..bef666275 100644 --- a/applications/main/infrared/scenes/infrared_scene_debug_settings.c +++ b/applications/main/infrared/scenes/infrared_scene_debug_settings.c @@ -18,6 +18,22 @@ static void infrared_scene_debug_settings_changed(VariableItem* item) { furi_hal_infrared_set_debug_out(value_index_ir); } + +static void infrared_scene_debug_settings_power_changed(VariableItem* item) { + bool value = variable_item_get_current_value_index(item); + if(value) { + for(int i = 0; i < 5 && !furi_hal_power_is_otg_enabled(); i++) { + furi_hal_power_enable_otg(); + furi_delay_ms(10); + } + } else { + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_disable_otg(); + } + } + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); +} + 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); @@ -42,6 +58,16 @@ void infrared_scene_debug_settings_on_enter(void* context) { 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]); + item = variable_item_list_add( + variable_item_list, + "Ext Module 5v", + 2, + infrared_scene_debug_settings_power_changed, + infrared); + bool enabled = furi_hal_power_is_otg_enabled(); + variable_item_set_current_value_index(item, enabled); + variable_item_set_current_value_text(item, enabled ? "ON" : "OFF"); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewVariableItemList); } diff --git a/applications/main/infrared/scenes/infrared_scene_start.c b/applications/main/infrared/scenes/infrared_scene_start.c index 816d57294..a89974ba2 100644 --- a/applications/main/infrared/scenes/infrared_scene_start.c +++ b/applications/main/infrared/scenes/infrared_scene_start.c @@ -3,10 +3,10 @@ enum SubmenuIndex { SubmenuIndexUniversalRemotes, SubmenuIndexLearnNewRemote, - SubmenuIndexLearnNewRemoteRaw, SubmenuIndexSavedRemotes, - SubmenuIndexDebug, - SubmenuIndexDebugSettings + SubmenuIndexDebugSettings, + SubmenuIndexLearnNewRemoteRaw, + SubmenuIndexDebug }; static void infrared_scene_start_submenu_callback(void* context, uint32_t index) { @@ -37,6 +37,12 @@ void infrared_scene_start_on_enter(void* context) { SubmenuIndexSavedRemotes, infrared_scene_start_submenu_callback, infrared); + submenu_add_item( + submenu, + "GPIO Settings", + SubmenuIndexDebugSettings, + infrared_scene_start_submenu_callback, + infrared); if(infrared->app_state.is_debug_enabled) { submenu_add_item( @@ -51,12 +57,6 @@ void infrared_scene_start_on_enter(void* context) { 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 = From d5100476ac6e2dcd3dc22d42d578b3497da196cb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 03:50:55 +0300 Subject: [PATCH 209/216] cleanup ext module settings --- .../scenes/subghz_scene_ext_module_settings.c | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) 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 e91ebd47f..fbdb22180 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -1,12 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -static uint8_t value_index_exm; -static uint8_t value_index_dpin; -static uint8_t value_index_cnt; -static uint8_t value_index_pwr; -static uint8_t value_index_time; - #define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const)) const char* const radio_modules_variables_text[] = { "Internal", @@ -40,7 +34,7 @@ const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { static void subghz_scene_ext_module_changed(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); - value_index_exm = variable_item_get_current_value_index(item); + uint8_t value_index_exm = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]); @@ -114,16 +108,17 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { SubGhz* subghz = context; VariableItemList* variable_item_list = subghz->variable_item_list; + uint8_t value_index; - value_index_exm = furi_hal_subghz.radio_type; + value_index = 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_exm); - variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]); item = variable_item_list_add( subghz->variable_item_list, @@ -131,9 +126,9 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { EXT_MOD_POWER_COUNT, subghz_scene_receiver_config_set_ext_mod_power, subghz); - value_index_pwr = furi_hal_subghz_get_external_power_disable(); - variable_item_set_current_value_index(item, value_index_pwr); - variable_item_set_current_value_text(item, ext_mod_power_text[value_index_pwr]); + value_index = furi_hal_subghz_get_external_power_disable(); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, ext_mod_power_text[value_index]); item = variable_item_list_add( subghz->variable_item_list, @@ -141,9 +136,9 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { TIMESTAMP_NAMES_COUNT, subghz_scene_receiver_config_set_timestamp_file_names, subghz); - value_index_time = furi_hal_subghz_get_timestamp_file_names(); - variable_item_set_current_value_index(item, value_index_time); - variable_item_set_current_value_text(item, timestamp_names_text[value_index_time]); + value_index = furi_hal_subghz_get_timestamp_file_names(); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, timestamp_names_text[value_index]); item = variable_item_list_add( subghz->variable_item_list, @@ -153,19 +148,19 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { subghz); switch(furi_hal_subghz_get_rolling_counter_mult()) { case 1: - value_index_cnt = 0; + value_index = 0; break; case 2: - value_index_cnt = 1; + value_index = 1; break; case 3: - value_index_cnt = 2; + value_index = 2; 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]); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, debug_counter_text[value_index]); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { item = variable_item_list_add( @@ -174,9 +169,9 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { DEBUG_P_COUNT, subghz_scene_receiver_config_set_debug_pin, subghz); - value_index_dpin = subghz_txrx_get_debug_pin_state(subghz->txrx); - variable_item_set_current_value_index(item, value_index_dpin); - variable_item_set_current_value_text(item, debug_pin_text[value_index_dpin]); + value_index = subghz_txrx_get_debug_pin_state(subghz->txrx); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, debug_pin_text[value_index]); } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); @@ -188,14 +183,14 @@ bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent UNUSED(event); // Set selected radio module - furi_hal_subghz_select_radio_type(value_index_exm); - furi_hal_subghz_init_radio_type(value_index_exm); + furi_hal_subghz_select_radio_type(subghz->last_settings->external_module_enabled); + furi_hal_subghz_init_radio_type(subghz->last_settings->external_module_enabled); furi_hal_subghz_enable_ext_power(); // Check if module is present, if no -> show error if(!furi_hal_subghz_check_radio()) { - value_index_exm = 0; + subghz->last_settings->external_module_enabled = false; furi_hal_subghz_select_radio_type(SubGhzRadioInternal); furi_hal_subghz_init_radio_type(SubGhzRadioInternal); furi_string_set(subghz->error_str, "Please connect\nexternal radio"); From 3881de74eb388ef7a462212c37b3871512d2f6f5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 03:54:53 +0300 Subject: [PATCH 210/216] rename settings scene --- applications/main/subghz/scenes/subghz_scene_config.h | 2 +- ..._ext_module_settings.c => subghz_scene_radio_settings.c} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename applications/main/subghz/scenes/{subghz_scene_ext_module_settings.c => subghz_scene_radio_settings.c} (96%) diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index 6fb183d60..269ec4c72 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -23,7 +23,7 @@ ADD_SCENE(subghz, set_fix, SetFix) ADD_SCENE(subghz, set_cnt, SetCnt) ADD_SCENE(subghz, set_seed, SetSeed) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) -ADD_SCENE(subghz, ext_module_settings, ExtModuleSettings) +ADD_SCENE(subghz, radio_settings, ExtModuleSettings) ADD_SCENE(subghz, read_raw, ReadRAW) ADD_SCENE(subghz, more_raw, MoreRAW) ADD_SCENE(subghz, decode_raw, DecodeRAW) diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_radio_settings.c similarity index 96% rename from applications/main/subghz/scenes/subghz_scene_ext_module_settings.c rename to applications/main/subghz/scenes/subghz_scene_radio_settings.c index fbdb22180..8e8d05019 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_radio_settings.c @@ -104,7 +104,7 @@ static void subghz_scene_receiver_config_set_timestamp_file_names(VariableItem* subghz_last_settings_save(subghz->last_settings); } -void subghz_scene_ext_module_settings_on_enter(void* context) { +void subghz_scene_radio_settings_on_enter(void* context) { SubGhz* subghz = context; VariableItemList* variable_item_list = subghz->variable_item_list; @@ -177,7 +177,7 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } -bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent event) { +bool subghz_scene_radio_settings_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; UNUSED(subghz); UNUSED(event); @@ -200,7 +200,7 @@ bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent return false; } -void subghz_scene_ext_module_settings_on_exit(void* context) { +void subghz_scene_radio_settings_on_exit(void* context) { SubGhz* subghz = context; variable_item_list_reset(subghz->variable_item_list); } From 9914aa40bd589d767b850d81b0e4eda28de46be9 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 11 May 2023 05:25:06 +0300 Subject: [PATCH 211/216] [FL-3302] Part 2 of hooking C2 IPC (#2662) --- firmware/targets/f7/ble_glue/ble_glue.c | 15 +++++++++++++++ lib/stm32wb.scons | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6b527cfca..1cb5501d9 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -2,6 +2,7 @@ #include "app_common.h" #include "ble_app.h" #include +#include #include #include @@ -72,6 +73,20 @@ void shci_register_io_bus(tSHciIO* fops) { fops->Send = ble_glue_TL_SYS_SendCmd; } +static int32_t ble_glue_TL_BLE_SendCmd(uint8_t* buffer, uint16_t size) { + if(furi_hal_bt_get_hardfault_info()) { + furi_crash("ST(R) Copro(R) HardFault"); + } + + return TL_BLE_SendCmd(buffer, size); +} + +void hci_register_io_bus(tHciIO* fops) { + /* Register IO bus services */ + fops->Init = TL_BLE_Init; + fops->Send = ble_glue_TL_BLE_SendCmd; +} + /////////////////////////////////////////////////////////////////////////////// void ble_glue_init() { diff --git a/lib/stm32wb.scons b/lib/stm32wb.scons index 7cb2fa8bd..94a1c7075 100644 --- a/lib/stm32wb.scons +++ b/lib/stm32wb.scons @@ -48,7 +48,10 @@ sources += Glob( ) sources += Glob( "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/*_tl*.c", - exclude="stm32wb_copro/wpan/interface/patterns/ble_thread/tl/shci_tl_if.c", + exclude=[ + "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/hci_tl_if.c", + "stm32wb_copro/wpan/interface/patterns/ble_thread/tl/shci_tl_if.c", + ], source=True, ) sources += [ From 9862876f06c967554c0979c035e1ed194f83f97d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 11 May 2023 06:10:20 +0300 Subject: [PATCH 212/216] SubGHz: Fix typos (#2661) Co-authored-by: hedger --- applications/debug/unit_tests/subghz/subghz_test.c | 8 ++++---- ...te_potocol_key.c => subghz_txrx_create_protocol_key.c} | 4 ++-- ...te_potocol_key.h => subghz_txrx_create_protocol_key.h} | 2 +- applications/main/subghz/scenes/subghz_scene_set_type.c | 6 +++--- lib/subghz/protocols/keeloq_common.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) rename applications/main/subghz/helpers/{subghz_txrx_create_potocol_key.c => subghz_txrx_create_protocol_key.c} (98%) rename applications/main/subghz/helpers/{subghz_txrx_create_potocol_key.h => subghz_txrx_create_protocol_key.h} (98%) diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index c7e9c96f1..f1ab92653 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -407,7 +407,7 @@ MU_TEST(subghz_decoder_ido_test) { "Test decoder " SUBGHZ_PROTOCOL_IDO_NAME " error\r\n"); } -MU_TEST(subghz_decoder_keelog_test) { +MU_TEST(subghz_decoder_keeloq_test) { mu_assert( subghz_decoder_test( EXT_PATH("unit_tests/subghz/doorhan_raw.sub"), SUBGHZ_PROTOCOL_KEELOQ_NAME), @@ -676,7 +676,7 @@ MU_TEST(subghz_encoder_nice_flo_test) { "Test encoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n"); } -MU_TEST(subghz_encoder_keelog_test) { +MU_TEST(subghz_encoder_keeloq_test) { mu_assert( subghz_encoder_test(EXT_PATH("unit_tests/subghz/doorhan.sub")), "Test encoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n"); @@ -813,7 +813,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_gate_tx_test); MU_RUN_TEST(subghz_decoder_hormann_hsm_test); MU_RUN_TEST(subghz_decoder_ido_test); - MU_RUN_TEST(subghz_decoder_keelog_test); + MU_RUN_TEST(subghz_decoder_keeloq_test); MU_RUN_TEST(subghz_decoder_kia_seed_test); MU_RUN_TEST(subghz_decoder_nero_radio_test); MU_RUN_TEST(subghz_decoder_nero_sketch_test); @@ -852,7 +852,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_came_twee_test); MU_RUN_TEST(subghz_encoder_gate_tx_test); MU_RUN_TEST(subghz_encoder_nice_flo_test); - MU_RUN_TEST(subghz_encoder_keelog_test); + MU_RUN_TEST(subghz_encoder_keeloq_test); MU_RUN_TEST(subghz_encoder_linear_test); MU_RUN_TEST(subghz_encoder_linear_delta3_test); MU_RUN_TEST(subghz_encoder_megacode_test); diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c similarity index 98% rename from applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c rename to applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c index 41e4f7c4e..06a855c23 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.c @@ -1,5 +1,5 @@ #include "subghz_txrx_i.h" -#include "subghz_txrx_create_potocol_key.h" +#include "subghz_txrx_create_protocol_key.h" #include #include #include @@ -84,7 +84,7 @@ bool subghz_txrx_gen_data_protocol_and_te( return ret; } -bool subghz_txrx_gen_keelog_protocol( +bool subghz_txrx_gen_keeloq_protocol( SubGhzTxRx* instance, const char* name_preset, uint32_t frequency, diff --git a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h similarity index 98% rename from applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h rename to applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h index 5eed93034..514a5733c 100644 --- a/applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h +++ b/applications/main/subghz/helpers/subghz_txrx_create_protocol_key.h @@ -54,7 +54,7 @@ bool subghz_txrx_gen_data_protocol_and_te( * @param cnt Counter * @return bool True if success */ -bool subghz_txrx_gen_keelog_protocol( +bool subghz_txrx_gen_keeloq_protocol( SubGhzTxRx* instance, const char* name_preset, uint32_t frequency, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 32e0d6588..d0571f1b1 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,5 +1,5 @@ #include "../subghz_i.h" -#include "../helpers/subghz_txrx_create_potocol_key.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" #include #include @@ -172,7 +172,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24); break; case SubmenuIndexDoorHan_433_92: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( @@ -181,7 +181,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } break; case SubmenuIndexDoorHan_315_00: - generated_protocol = subghz_txrx_gen_keelog_protocol( + generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003); if(!generated_protocol) { furi_string_set( diff --git a/lib/subghz/protocols/keeloq_common.c b/lib/subghz/protocols/keeloq_common.c index ddbf1c917..041494f90 100644 --- a/lib/subghz/protocols/keeloq_common.c +++ b/lib/subghz/protocols/keeloq_common.c @@ -23,7 +23,7 @@ inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const } /** Simple Learning Decrypt - * @param data - keelog encrypt data + * @param data - keeloq encrypt data * @param key - manufacture (64bit) * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter */ From aa8a369e2a175fff226a84c75126eac8d24d625e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 11 May 2023 18:50:17 +0900 Subject: [PATCH 213/216] Rpc: add desktop service. Desktop: refactor locking routine. (#2665) * Rpc: add desktop service * Protobuf: sync to latest release. Desktop: rewrite PIN locking, finalize locking API * Desktop: cleanup code a little bit --- applications/services/desktop/desktop.c | 41 ++++- applications/services/desktop/desktop.h | 6 + .../services/desktop/desktop_settings.h | 3 +- applications/services/desktop/helpers/pin.c | 74 +++++++++ applications/services/desktop/helpers/pin.h | 11 ++ .../services/desktop/helpers/pin_lock.c | 140 ------------------ .../services/desktop/helpers/pin_lock.h | 21 --- .../desktop/scenes/desktop_scene_lock_menu.c | 19 +-- .../desktop/scenes/desktop_scene_locked.c | 4 +- .../desktop/scenes/desktop_scene_pin_input.c | 8 +- .../services/desktop/views/desktop_events.h | 1 - .../desktop/views/desktop_view_lock_menu.c | 14 +- .../desktop/views/desktop_view_lock_menu.h | 2 - .../views/desktop_view_pin_setup_done.c | 79 ---------- .../views/desktop_view_pin_setup_done.h | 15 -- applications/services/rpc/rpc.c | 4 + applications/services/rpc/rpc_desktop.c | 73 +++++++++ applications/services/rpc/rpc_i.h | 3 + .../scenes/desktop_settings_scene_pin_auth.c | 4 +- .../scenes/desktop_settings_scene_pin_error.c | 2 +- .../scenes/desktop_settings_scene_pin_setup.c | 4 +- assets/protobuf | 2 +- 22 files changed, 222 insertions(+), 308 deletions(-) create mode 100644 applications/services/desktop/helpers/pin.c create mode 100644 applications/services/desktop/helpers/pin.h delete mode 100644 applications/services/desktop/helpers/pin_lock.c delete mode 100644 applications/services/desktop/helpers/pin_lock.h delete mode 100644 applications/services/desktop/views/desktop_view_pin_setup_done.c delete mode 100644 applications/services/desktop/views/desktop_view_pin_setup_done.h create mode 100644 applications/services/rpc/rpc_desktop.c diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index bdb730099..28d09cc0d 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "animations/animation_manager.h" #include "desktop/scenes/desktop_scene.h" @@ -14,7 +16,7 @@ #include "desktop/views/desktop_view_pin_input.h" #include "desktop/views/desktop_view_pin_timeout.h" #include "desktop_i.h" -#include "helpers/pin_lock.h" +#include "helpers/pin.h" #include "helpers/slideshow_filename.h" #define TAG "Desktop" @@ -132,6 +134,15 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } void desktop_lock(Desktop* desktop) { + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + furi_hal_rtc_set_pin_fails(0); + + if(desktop->settings.pin_code.length) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_record_close(RECORD_CLI); + } + desktop_auto_lock_inhibit(desktop); scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); @@ -147,6 +158,13 @@ void desktop_unlock(Desktop* desktop) { desktop_view_locked_unlock(desktop->locked_view); scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); desktop_auto_lock_arm(desktop); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + + if(desktop->settings.pin_code.length) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + } } void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { @@ -290,11 +308,14 @@ Desktop* desktop_alloc() { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); + furi_record_create(RECORD_DESKTOP, desktop); + return desktop; } void desktop_free(Desktop* desktop) { furi_assert(desktop); + furi_check(furi_record_destroy(RECORD_DESKTOP)); furi_pubsub_unsubscribe( loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription); @@ -352,6 +373,16 @@ static bool desktop_check_file_flag(const char* flag_path) { return exists; } +bool desktop_api_is_locked(Desktop* instance) { + furi_assert(instance); + return furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock); +} + +void desktop_api_unlock(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopLockedEventUnlocked); +} + int32_t desktop_srv(void* p) { UNUSED(p); @@ -375,14 +406,12 @@ int32_t desktop_srv(void* p) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - desktop_pin_lock_init(&desktop->settings); - - if(!desktop_pin_lock_is_locked()) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { + desktop_lock(desktop); + } else { if(!loader_is_locked(desktop->loader)) { desktop_auto_lock_arm(desktop); } - } else { - desktop_lock(desktop); } if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) { diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index f5608207d..5b12647b8 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -1,3 +1,9 @@ #pragma once typedef struct Desktop Desktop; + +#define RECORD_DESKTOP "desktop" + +bool desktop_api_is_locked(Desktop* instance); + +void desktop_api_unlock(Desktop* instance); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index e502c35f2..5d1b6126f 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (6) +#define DESKTOP_SETTINGS_VER (7) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -52,7 +52,6 @@ typedef struct { FavoriteApp favorite_primary; FavoriteApp favorite_secondary; PinCode pin_code; - uint8_t is_locked; uint32_t auto_lock_delay_ms; uint8_t dummy_mode; } DesktopSettings; diff --git a/applications/services/desktop/helpers/pin.c b/applications/services/desktop/helpers/pin.c new file mode 100644 index 000000000..8a79a1fb8 --- /dev/null +++ b/applications/services/desktop/helpers/pin.c @@ -0,0 +1,74 @@ +#include "pin.h" + +#include +#include +#include +#include +#include +#include + +#include "../desktop_i.h" + +static const NotificationSequence sequence_pin_fail = { + &message_display_backlight_on, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + + &message_delay_250, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + NULL, +}; + +static const uint8_t desktop_helpers_fails_timeout[] = { + 0, + 0, + 0, + 0, + 30, + 60, + 90, + 120, + 150, + 180, + /* +60 for every next fail */ +}; + +void desktop_pin_lock_error_notify() { + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message(notification, &sequence_pin_fail); + furi_record_close(RECORD_NOTIFICATION); +} + +uint32_t desktop_pin_lock_get_fail_timeout() { + uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); + uint32_t pin_timeout = 0; + uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; + if(pin_fails <= max_index) { + pin_timeout = desktop_helpers_fails_timeout[pin_fails]; + } else { + pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; + } + + return pin_timeout; +} + +bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2) { + furi_assert(pin_code1); + furi_assert(pin_code2); + bool result = false; + + if(pin_code1->length == pin_code2->length) { + result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length); + } + + return result; +} diff --git a/applications/services/desktop/helpers/pin.h b/applications/services/desktop/helpers/pin.h new file mode 100644 index 000000000..e5410723e --- /dev/null +++ b/applications/services/desktop/helpers/pin.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include +#include "../desktop.h" +#include + +void desktop_pin_lock_error_notify(); + +uint32_t desktop_pin_lock_get_fail_timeout(); + +bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2); diff --git a/applications/services/desktop/helpers/pin_lock.c b/applications/services/desktop/helpers/pin_lock.c deleted file mode 100644 index 22fcabe7d..000000000 --- a/applications/services/desktop/helpers/pin_lock.c +++ /dev/null @@ -1,140 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include "../helpers/pin_lock.h" -#include "../desktop_i.h" -#include -#include - -static const NotificationSequence sequence_pin_fail = { - &message_display_backlight_on, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - - &message_delay_250, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - NULL, -}; - -static const uint8_t desktop_helpers_fails_timeout[] = { - 0, - 0, - 0, - 0, - 30, - 60, - 90, - 120, - 150, - 180, - /* +60 for every next fail */ -}; - -void desktop_pin_lock_error_notify() { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_pin_fail); - furi_record_close(RECORD_NOTIFICATION); -} - -uint32_t desktop_pin_lock_get_fail_timeout() { - uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); - uint32_t pin_timeout = 0; - uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; - if(pin_fails <= max_index) { - pin_timeout = desktop_helpers_fails_timeout[pin_fails]; - } else { - pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; - } - - return pin_timeout; -} - -void desktop_pin_lock(DesktopSettings* settings) { - furi_assert(settings); - - furi_hal_rtc_set_pin_fails(0); - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_close(cli); - furi_record_close(RECORD_CLI); - settings->is_locked = 1; - DESKTOP_SETTINGS_SAVE(settings); -} - -void desktop_pin_unlock(DesktopSettings* settings) { - furi_assert(settings); - - furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_open(cli, &cli_vcp); - furi_record_close(RECORD_CLI); - settings->is_locked = 0; - DESKTOP_SETTINGS_SAVE(settings); -} - -void desktop_pin_lock_init(DesktopSettings* settings) { - furi_assert(settings); - - if(settings->pin_code.length > 0) { - if(settings->is_locked == 1) { - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - } else { - if(desktop_pin_lock_is_locked()) { - settings->is_locked = 1; - DESKTOP_SETTINGS_SAVE(settings); - } - } - } else { - furi_hal_rtc_set_pin_fails(0); - furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - } - - if(desktop_pin_lock_is_locked()) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_close(cli); - furi_record_close(RECORD_CLI); - } -} - -bool desktop_pin_lock_verify(const PinCode* pin_set, const PinCode* pin_entered) { - bool result = false; - if(desktop_pins_are_equal(pin_set, pin_entered)) { - furi_hal_rtc_set_pin_fails(0); - result = true; - } else { - uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); - furi_hal_rtc_set_pin_fails(pin_fails + 1); - result = false; - } - return result; -} - -bool desktop_pin_lock_is_locked() { - return furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock); -} - -bool desktop_pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) { - furi_assert(pin_code1); - furi_assert(pin_code2); - bool result = false; - - if(pin_code1->length == pin_code2->length) { - result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length); - } - - return result; -} diff --git a/applications/services/desktop/helpers/pin_lock.h b/applications/services/desktop/helpers/pin_lock.h deleted file mode 100644 index 028ae6d22..000000000 --- a/applications/services/desktop/helpers/pin_lock.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include -#include "../desktop.h" -#include - -void desktop_pin_lock_error_notify(); - -uint32_t desktop_pin_lock_get_fail_timeout(); - -void desktop_pin_lock(DesktopSettings* settings); - -void desktop_pin_unlock(DesktopSettings* settings); - -bool desktop_pin_lock_is_locked(); - -void desktop_pin_lock_init(DesktopSettings* settings); - -bool desktop_pin_lock_verify(const PinCode* pin_set, const PinCode* pin_entered); - -bool desktop_pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2); diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index bfaa8a036..105b2b37a 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -10,7 +10,7 @@ #include "../views/desktop_view_lock_menu.h" #include "desktop_scene_i.h" #include "desktop_scene.h" -#include "../helpers/pin_lock.h" +#include "../helpers/pin.h" #define TAG "DesktopSceneLock" @@ -25,7 +25,6 @@ void desktop_scene_lock_menu_on_enter(void* context) { DESKTOP_SETTINGS_LOAD(&desktop->settings); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); - desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0); desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); desktop_lock_menu_set_stealth_mode_state( desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)); @@ -44,7 +43,6 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { if(check_pin_changed) { DESKTOP_SETTINGS_LOAD(&desktop->settings); if(desktop->settings.pin_code.length > 0) { - desktop_lock_menu_set_pin_state(desktop->lock_menu, true); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } } @@ -55,21 +53,6 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { desktop_lock(desktop); consumed = true; break; - case DesktopLockMenuEventPinLock: - if(desktop->settings.pin_code.length > 0) { - desktop_pin_lock(&desktop->settings); - desktop_lock(desktop); - } else { - LoaderStatus status = - loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG); - if(status == LoaderStatusOk) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); - } else { - FURI_LOG_E(TAG, "Unable to start desktop settings"); - } - } - consumed = true; - break; case DesktopLockMenuEventDummyModeOn: desktop_set_dummy_mode_state(desktop, true); scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/services/desktop/scenes/desktop_scene_locked.c b/applications/services/desktop/scenes/desktop_scene_locked.c index af19efc74..f64ef8371 100644 --- a/applications/services/desktop/scenes/desktop_scene_locked.c +++ b/applications/services/desktop/scenes/desktop_scene_locked.c @@ -7,7 +7,7 @@ #include "../desktop.h" #include "../desktop_i.h" -#include "../helpers/pin_lock.h" +#include "../helpers/pin.h" #include "../animations/animation_manager.h" #include "../views/desktop_events.h" #include "../views/desktop_view_pin_input.h" @@ -45,7 +45,7 @@ void desktop_scene_locked_on_enter(void* context) { bool switch_to_timeout_scene = false; uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked); if(state == SCENE_LOCKED_FIRST_ENTER) { - bool pin_locked = desktop_pin_lock_is_locked(); + bool pin_locked = desktop->settings.pin_code.length > 0; view_port_enabled_set(desktop->lock_icon_viewport, true); Gui* gui = furi_record_open(RECORD_GUI); gui_set_lockdown(gui, true); diff --git a/applications/services/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c index 9392309e6..157acebf5 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_input.c @@ -12,7 +12,7 @@ #include "../animations/animation_manager.h" #include "../views/desktop_events.h" #include "../views/desktop_view_pin_input.h" -#include "../helpers/pin_lock.h" +#include "../helpers/pin.h" #include "desktop_scene.h" #include "desktop_scene_i.h" @@ -54,9 +54,12 @@ static void desktop_scene_pin_input_back_callback(void* context) { static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) { Desktop* desktop = (Desktop*)context; - if(desktop_pin_lock_verify(&desktop->settings.pin_code, pin_code)) { + if(desktop_pin_compare(&desktop->settings.pin_code, pin_code)) { + furi_hal_rtc_set_pin_fails(0); view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked); } else { + uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); + furi_hal_rtc_set_pin_fails(pin_fails + 1); view_dispatcher_send_custom_event( desktop->view_dispatcher, DesktopPinInputEventUnlockFailed); } @@ -126,7 +129,6 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopPinInputEventUnlocked: - desktop_pin_unlock(&desktop->settings); desktop_unlock(desktop); consumed = true; break; diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 983e84438..e366885fe 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -31,7 +31,6 @@ typedef enum { DesktopDebugEventExit, DesktopLockMenuEventLock, - DesktopLockMenuEventPinLock, DesktopLockMenuEventDummyModeOn, DesktopLockMenuEventDummyModeOff, DesktopLockMenuEventStealthModeOn, diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 8b25a890f..f4790ebb8 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -23,14 +23,6 @@ void desktop_lock_menu_set_callback( lock_menu->context = context; } -void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set) { - with_view_model( - lock_menu->view, - DesktopLockMenuViewModel * model, - { model->pin_is_set = pin_is_set; }, - true); -} - void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode) { with_view_model( lock_menu->view, @@ -102,7 +94,6 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { bool consumed = false; bool dummy_mode = false; bool stealth_mode = false; - bool pin_is_set = false; bool update = false; with_view_model( @@ -131,15 +122,12 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { idx = model->idx; dummy_mode = model->dummy_mode; stealth_mode = model->stealth_mode; - pin_is_set = model->pin_is_set; }, update); if(event->key == InputKeyOk) { if((idx == DesktopLockMenuIndexLock)) { - if((pin_is_set) && (event->type == InputTypeShort)) { - lock_menu->callback(DesktopLockMenuEventPinLock, lock_menu->context); - } else if((pin_is_set == false) && (event->type == InputTypeShort)) { + if((event->type == InputTypeShort)) { lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); } } else if(idx == DesktopLockMenuIndexStealth) { diff --git a/applications/services/desktop/views/desktop_view_lock_menu.h b/applications/services/desktop/views/desktop_view_lock_menu.h index 03ce6fa80..8ac3a7273 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.h +++ b/applications/services/desktop/views/desktop_view_lock_menu.h @@ -17,7 +17,6 @@ struct DesktopLockMenuView { typedef struct { uint8_t idx; - bool pin_is_set; bool dummy_mode; bool stealth_mode; } DesktopLockMenuViewModel; @@ -28,7 +27,6 @@ void desktop_lock_menu_set_callback( void* context); View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); -void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set); void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode); void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode); void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); diff --git a/applications/services/desktop/views/desktop_view_pin_setup_done.c b/applications/services/desktop/views/desktop_view_pin_setup_done.c deleted file mode 100644 index 561b12861..000000000 --- a/applications/services/desktop/views/desktop_view_pin_setup_done.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../desktop_i.h" -#include "desktop_view_pin_setup_done.h" - -struct DesktopViewPinSetupDone { - View* view; - DesktopViewPinSetupDoneDoneCallback callback; - void* context; -}; - -static void desktop_view_pin_done_draw(Canvas* canvas, void* model) { - furi_assert(canvas); - UNUSED(model); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned( - canvas, 64, 0, AlignCenter, AlignTop, "Prepare to use\narrows as\nPIN symbols"); - - canvas_set_font(canvas, FontSecondary); - elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols"); - - canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29); - elements_button_right(canvas, "Next"); -} - -static bool desktop_view_pin_done_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - - DesktopViewPinSetupDone* instance = context; - bool consumed = false; - - if((event->key == InputKeyRight) && (event->type == InputTypeShort)) { - instance->callback(instance->context); - consumed = true; - } - - return consumed; -} - -void desktop_view_pin_done_set_callback( - DesktopViewPinSetupDone* instance, - DesktopViewPinSetupDoneDoneCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - instance->callback = callback; - instance->context = context; -} - -DesktopViewPinSetupDone* desktop_view_pin_done_alloc() { - DesktopViewPinSetupDone* view = malloc(sizeof(DesktopViewPinSetupDone)); - view->view = view_alloc(); - view_set_context(view->view, view); - view_set_draw_callback(view->view, desktop_view_pin_done_draw); - view_set_input_callback(view->view, desktop_view_pin_done_input); - - return view; -} - -void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance) { - furi_assert(instance); - - view_free(instance->view); - free(instance); -} - -View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance) { - furi_assert(instance); - return instance->view; -} diff --git a/applications/services/desktop/views/desktop_view_pin_setup_done.h b/applications/services/desktop/views/desktop_view_pin_setup_done.h deleted file mode 100644 index b55677dc5..000000000 --- a/applications/services/desktop/views/desktop_view_pin_setup_done.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -typedef struct DesktopViewPinSetupDone DesktopViewPinSetupDone; - -typedef void (*DesktopViewPinSetupDoneDoneCallback)(void*); - -void desktop_view_pin_done_set_callback( - DesktopViewPinSetupDone* instance, - DesktopViewPinSetupDoneDoneCallback callback, - void* context); -DesktopViewPinSetupDone* desktop_view_pin_done_alloc(); -void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance); -View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance); diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index a759a12a9..b3ed4417c 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -57,6 +57,10 @@ static RpcSystemCallbacks rpc_systems[] = { .alloc = rpc_system_property_alloc, .free = NULL, }, + { + .alloc = rpc_desktop_alloc, + .free = rpc_desktop_free, + }, }; struct RpcSession { diff --git a/applications/services/rpc/rpc_desktop.c b/applications/services/rpc/rpc_desktop.c new file mode 100644 index 000000000..dbf9796ec --- /dev/null +++ b/applications/services/rpc/rpc_desktop.c @@ -0,0 +1,73 @@ +#include "flipper.pb.h" +#include "rpc_i.h" +#include +#include "desktop.pb.h" + +#define TAG "RpcDesktop" + +typedef struct { + RpcSession* session; + Desktop* desktop; +} RpcDesktop; + +static void rpc_desktop_on_is_locked_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_is_locked_request_tag); + + FURI_LOG_D(TAG, "IsLockedRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + PB_CommandStatus ret = desktop_api_is_locked(rpc_desktop->desktop) ? PB_CommandStatus_OK : + PB_CommandStatus_ERROR; + + rpc_send_and_release_empty(session, request->command_id, ret); +} + +static void rpc_desktop_on_unlock_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_unlock_request_tag); + + FURI_LOG_D(TAG, "UnlockRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + desktop_api_unlock(rpc_desktop->desktop); + + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); +} + +void* rpc_desktop_alloc(RpcSession* session) { + furi_assert(session); + + RpcDesktop* rpc_desktop = malloc(sizeof(RpcDesktop)); + rpc_desktop->desktop = furi_record_open(RECORD_DESKTOP); + rpc_desktop->session = session; + + RpcHandler rpc_handler = { + .message_handler = NULL, + .decode_submessage = NULL, + .context = rpc_desktop, + }; + + rpc_handler.message_handler = rpc_desktop_on_is_locked_request; + rpc_add_handler(session, PB_Main_desktop_is_locked_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_desktop_on_unlock_request; + rpc_add_handler(session, PB_Main_desktop_unlock_request_tag, &rpc_handler); + + return rpc_desktop; +} + +void rpc_desktop_free(void* context) { + furi_assert(context); + RpcDesktop* rpc_desktop = context; + + furi_assert(rpc_desktop->desktop); + furi_record_close(RECORD_DESKTOP); + + rpc_desktop->session = NULL; + free(rpc_desktop); +} \ No newline at end of file diff --git a/applications/services/rpc/rpc_i.h b/applications/services/rpc/rpc_i.h index 91a176da8..16e5e594d 100644 --- a/applications/services/rpc/rpc_i.h +++ b/applications/services/rpc/rpc_i.h @@ -36,6 +36,9 @@ void* rpc_system_gpio_alloc(RpcSession* session); void rpc_system_gpio_free(void* ctx); void* rpc_system_property_alloc(RpcSession* session); +void* rpc_desktop_alloc(RpcSession* session); +void rpc_desktop_free(void* ctx); + void rpc_debug_print_message(const PB_Main* message); void rpc_debug_print_data(const char* prefix, uint8_t* buffer, size_t size); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c index 5fed235ce..be2ee4825 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../desktop_settings_app.h" #include #include @@ -18,7 +18,7 @@ static void pin_auth_done_callback(const PinCode* pin_code, void* context) { DesktopSettingsApp* app = context; app->pincode_buffer = *pin_code; - if(desktop_pins_are_equal(&app->settings.pin_code, pin_code)) { + if(desktop_pin_compare(&app->settings.pin_code, pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c index dd1e85795..508992cee 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c @@ -6,7 +6,7 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #include "../desktop_settings_app.h" #define SCENE_EVENT_EXIT (0U) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c index bf0f48ae6..1603aa337 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c @@ -7,7 +7,7 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #define SCENE_EVENT_EXIT (0U) #define SCENE_EVENT_1ST_PIN_ENTERED (1U) @@ -25,7 +25,7 @@ static void pin_setup_done_callback(const PinCode* pin_code, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED); } else { app->pincode_buffer_filled = false; - if(desktop_pins_are_equal(&app->pincode_buffer, pin_code)) { + if(desktop_pin_compare(&app->pincode_buffer, pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); diff --git a/assets/protobuf b/assets/protobuf index 1f6b4a08c..a13c5ddd0 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 1f6b4a08c5d05c2b17926a3ba79f60109638932f +Subproject commit a13c5ddd0397511bd4c6de4afdd1031a5b6f5bca From b28480623a2e5ed46562e6852919908a64452d21 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Fri, 12 May 2023 22:07:30 +0100 Subject: [PATCH 214/216] Fix default mac addr for bt remote --- firmware/targets/f7/furi_hal/furi_hal_bt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 3378f07fc..a56f54484 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -214,8 +214,12 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, GapEventCallback event_cb, config->adv_service_uuid |= furi_hal_version_get_hw_color(); } else if(profile == FuriHalBtProfileHidKeyboard) { // Change MAC address for HID profile - uint8_t default_mac[GAP_MAC_ADDR_SIZE] = FURI_HAL_BT_DEFAULT_MAC_ADDR; - if(memcmp(config->mac_address, default_mac, 6) == 0) { + uint8_t default_mac[sizeof(config->mac_address)] = FURI_HAL_BT_DEFAULT_MAC_ADDR; + const uint8_t* normal_mac = furi_hal_version_get_ble_mac(); + if(memcmp(config->mac_address, default_mac, sizeof(config->mac_address)) == 0) { + memcpy(config->mac_address, normal_mac, sizeof(config->mac_address)); + } + if(memcmp(config->mac_address, normal_mac, sizeof(config->mac_address)) == 0) { config->mac_address[2]++; } // Change name Flipper -> Control From d4daa046094136e2969f8500d4dda4cd9d57df0e Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Sat, 6 May 2023 22:23:37 +0900 Subject: [PATCH 215/216] FuriHal: always clock SMPS from HSI --- firmware/targets/f7/furi_hal/furi_hal_clock.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index a76fbfbca..6283efabc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -76,6 +76,10 @@ void furi_hal_clock_init() { LL_RCC_LSI1_Enable(); while(!LS_CLOCK_IS_READY()) ; + + /* RF wakeup */ + LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); + LL_EXTI_EnableIT_0_31( LL_EXTI_LINE_18); /* Why? Because that's why. See RM0434, Table 61. CPU1 vector table. */ LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_18); @@ -145,7 +149,7 @@ void furi_hal_clock_init() { LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0 - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); @@ -208,8 +212,8 @@ void furi_hal_clock_switch_to_hsi() { while(!LL_RCC_HSI_IsReady()) ; - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); + furi_assert(LL_RCC_GetSMPSClockSource() == LL_RCC_SMPS_CLKSOURCE_HSI); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) ; @@ -240,7 +244,6 @@ void furi_hal_clock_switch_to_pll() { ; LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) ; From f71f5408500a6937b4a351f1b6137a450236d6bc Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 11 May 2023 17:06:26 -0600 Subject: [PATCH 216/216] nfc: Fix MFUL tearing flags read --- lib/nfc/protocols/mifare_ultralight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index 1cea2c392..e0a21a043 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -703,7 +703,7 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight FURI_LOG_D(TAG, "Reading tearing flags"); for(size_t i = 0; i < 3; i++) { tx_rx->tx_data[0] = MF_UL_CHECK_TEARING; - tx_rx->rx_data[1] = i; + tx_rx->tx_data[1] = i; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; if(!furi_hal_nfc_tx_rx(tx_rx, 50)) {