From 9ffcc52ada215be47a1921875ada955d3420e0be Mon Sep 17 00:00:00 2001 From: Vitaliya Chumakova Date: Sun, 7 Aug 2022 18:09:00 +0300 Subject: [PATCH 01/26] Mifare Ultralight authentication (#1365) * mifare ultralight auth prototype * it works! * Reference source * use countof * rework everything * oops forgot scenes * build: revert changes in manifest, stack size * build: fix buid, format sources * nfc: update unlock ultralight GUI * nfc: fix byte input header * nfc: add new scenes for locked ultralight * nfc: add data read to ultralights * nfc: add unlock option in mf ultralight menu * nfc: add data read init in ultralight generation * nfc: lin sources, fix unlocked save * nfc: format python sources * nfc: clean up Co-authored-by: gornekich --- applications/nfc/application.fam | 2 +- applications/nfc/helpers/nfc_generators.c | 4 + applications/nfc/nfc_i.h | 0 applications/nfc/scenes/nfc_scene_config.h | 5 + .../nfc/scenes/nfc_scene_extra_actions.c | 9 ++ .../nfc_scene_mf_ultralight_key_input.c | 44 ++++++ .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 19 ++- .../nfc_scene_mf_ultralight_read_auth.c | 107 +++++++++++++++ ...nfc_scene_mf_ultralight_read_auth_result.c | 98 ++++++++++++++ .../nfc_scene_mf_ultralight_read_success.c | 94 +++++++------ .../nfc_scene_mf_ultralight_unlock_menu.c | 70 ++++++++++ .../nfc_scene_mf_ultralight_unlock_warn.c | 45 +++++++ firmware.scons | 2 +- lib/SConscript | 6 +- lib/mbedtls.scons | 6 +- lib/nfc/nfc_device.c | 29 +++- lib/nfc/nfc_worker.c | 70 ++++++++-- lib/nfc/nfc_worker.h | 5 + lib/nfc/nfc_worker_i.h | 4 + lib/nfc/parsers/nfc_supported_card.c | 13 +- lib/nfc/protocols/mifare_ultralight.c | 125 +++++++++++++++++- lib/nfc/protocols/mifare_ultralight.h | 33 +++++ 22 files changed, 717 insertions(+), 73 deletions(-) mode change 100755 => 100644 applications/nfc/nfc_i.h create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c mode change 100755 => 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam index f43ed3144..ce21bfd27 100644 --- a/applications/nfc/application.fam +++ b/applications/nfc/application.fam @@ -10,7 +10,7 @@ App( ], provides=["nfc_start"], icon="A_NFC_14", - stack_size=4 * 1024, + stack_size=5 * 1024, order=30, ) diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index 066ac9d1b..3ec78a127 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/nfc/helpers/nfc_generators.c @@ -55,6 +55,7 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeUnknown; mful->data_size = 16 * 4; + mful->data_read = mful->data_size; nfc_generate_mf_ul_copy_uid_with_bcc(data); // TODO: what's internal byte on page 2? memset(&mful->data[4 * 4], 0xFF, 4); @@ -67,6 +68,7 @@ static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeNTAG203; mful->data_size = 42 * 4; + mful->data_read = mful->data_size; nfc_generate_mf_ul_copy_uid_with_bcc(data); mful->data[9] = 0x48; // Internal byte memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203)); @@ -78,6 +80,7 @@ static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t n MfUltralightData* mful = &data->mf_ul_data; mful->data_size = num_pages * 4; + mful->data_read = mful->data_size; nfc_generate_mf_ul_copy_uid_with_bcc(data); uint16_t config_index = (num_pages - 4) * 4; mful->data[config_index] = 0x04; // STRG_MOD_EN @@ -180,6 +183,7 @@ static void mful->type = type; memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); mful->data_size = num_pages * 4; + mful->data_read = mful->data_size; memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len); mful->data[7] = data->nfc_data.sak; mful->data[8] = data->nfc_data.atqa[0]; diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h old mode 100755 new mode 100644 diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index de8de6b40..584faf309 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -15,6 +15,11 @@ ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) +ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) +ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult) +ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) +ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) +ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) diff --git a/applications/nfc/scenes/nfc_scene_extra_actions.c b/applications/nfc/scenes/nfc_scene_extra_actions.c index 823a4ace0..43e49e5a0 100644 --- a/applications/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/nfc/scenes/nfc_scene_extra_actions.c @@ -2,6 +2,7 @@ enum SubmenuIndex { SubmenuIndexMfClassicKeys, + SubmenuIndexMfUltralightUnlock, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { @@ -20,6 +21,12 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, nfc); + submenu_add_item( + submenu, + "Unlock NTAG/Ultralight", + SubmenuIndexMfUltralightUnlock, + nfc_scene_extra_actions_submenu_callback, + nfc); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } @@ -35,6 +42,8 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } consumed = true; + } else if(event.event == SubmenuIndexMfUltralightUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c new file mode 100644 index 000000000..089187d5b --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_key_input.c @@ -0,0 +1,44 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_ultralight_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_mf_ultralight_key_input_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 4); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_ultralight_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, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_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/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c index e3d256a55..9174a8b19 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -1,6 +1,7 @@ #include "../nfc_i.h" enum SubmenuIndex { + SubmenuIndexUnlock, SubmenuIndexSave, SubmenuIndexEmulate, }; @@ -14,7 +15,16 @@ void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index void nfc_scene_mf_ultralight_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; + MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; + if(data->data_read != data->data_size) { + submenu_add_item( + submenu, + "Unlock With Password", + SubmenuIndexUnlock, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); submenu_add_item( @@ -35,19 +45,20 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave); nfc->dev->format = NfcDeviceSaveFormatMifareUl; // 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_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); consumed = true; + } else if(event.event == SubmenuIndexUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); + } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_previous_scene(nfc->scene_manager); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c new file mode 100644 index 000000000..968157bdb --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -0,0 +1,107 @@ +#include "../nfc_i.h" +#include + +typedef enum { + NfcSceneMfUlReadStateIdle, + NfcSceneMfUlReadStateDetecting, + NfcSceneMfUlReadStateReading, + NfcSceneMfUlReadStateNotSupportedCard, +} NfcSceneMfUlReadState; + +bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { + Nfc* nfc = context; + + if(event == NfcWorkerEventMfUltralightPassKey) { + memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + } + return true; +} + +void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) { + uint32_t curr_state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + if(curr_state != state) { + if(state == NfcSceneMfUlReadStateDetecting) { + popup_reset(nfc->popup); + popup_set_text( + nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual); + } else if(state == NfcSceneMfUlReadStateReading) { + popup_reset(nfc->popup); + popup_set_header( + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); + } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { + popup_reset(nfc->popup); + popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + nfc->popup, + "Only MIFARE\nUltralight & NTAG\n are supported", + 4, + 22, + AlignLeft, + AlignTop); + popup_set_icon(nfc->popup, 73, 17, &I_DolphinFirstStart8_56x51); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); + } +} + +void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcRead); + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateReadMfUltralightReadAuth, + &nfc->dev->dev_data, + nfc_scene_mf_ultralight_read_auth_worker_callback, + nfc); + + nfc_blink_start(nfc); +} + +bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state( + nfc, NfcSceneMfUlReadStateNotSupportedCard); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } + return consumed; +} + +void nfc_scene_mf_ultralight_read_auth_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, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c new file mode 100644 index 000000000..b94215455 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -0,0 +1,98 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_mf_ultralight_read_auth_result_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + Nfc* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Setup dialog view + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data); + Widget* widget = nfc->widget; + string_t temp_str; + string_init(temp_str); + + if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { + widget_add_string_element( + widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!"); + } else { + widget_add_string_element( + widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!"); + } + string_set_str(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + widget_add_string_element( + widget, 0, 17, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + if(mf_ul_data->auth_success) { + string_printf( + temp_str, + "Password: %02X %02X %02X %02X", + config_pages->auth_data.pwd.raw[0], + config_pages->auth_data.pwd.raw[1], + config_pages->auth_data.pwd.raw[2], + config_pages->auth_data.pwd.raw[3]); + widget_add_string_element( + widget, 0, 28, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + string_printf( + temp_str, + "PACK: %02X %02X", + config_pages->auth_data.pack.raw[0], + config_pages->auth_data.pack.raw[1]); + widget_add_string_element( + widget, 0, 39, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + } + string_printf( + temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); + widget_add_string_element( + widget, 0, 50, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "Save", + nfc_scene_mf_ultralight_read_auth_result_widget_callback, + nfc); + + string_clear(temp_str); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + nfc->dev->format = NfcDeviceSaveFormatMifareUl; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } + + return consumed; +} + +void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { + Nfc* nfc = context; + + // Clean views + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c old mode 100755 new mode 100644 index 8b1b6c004..65750b963 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,51 +1,67 @@ #include "../nfc_i.h" #include -#define NFC_SCENE_READ_SUCCESS_SHIFT " " - enum { - ReadMifareUlStateShowUID, + ReadMifareUlStateShowInfo, ReadMifareUlStateShowData, }; -void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) { +void nfc_scene_mf_ultralight_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } } void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // Setup dialog view + // Setup widget view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_center_button_text(dialog_ex, "Data"); - dialog_ex_set_header( - dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter); - dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); - // Display UID - nfc_text_store_set( - nfc, - NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X\n" NFC_SCENE_READ_SUCCESS_SHIFT - "SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", - data->atqa[0], - data->atqa[1], - data->sak, - data->uid[0], - data->uid[1], - data->uid[2], - data->uid[3], - data->uid[4], - data->uid[5], - data->uid[6]); - dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback); + Widget* widget = nfc->widget; + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + widget_add_button_element( + widget, + GuiButtonTypeCenter, + "Data", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); + string_t data_str; + string_init_printf(data_str, "UID:"); + for(size_t i = 0; i < data->uid_len; i++) { + string_cat_printf(data_str, " %02X", data->uid[i]); + } + widget_add_string_element( + widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); + string_printf( + data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); + widget_add_string_element( + widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); + if(mf_ul_data->data_read != mf_ul_data->data_size) { + widget_add_string_element( + widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!"); + } + string_clear(data_str); // Setup TextBox view TextBox* text_box = nfc->text_box; @@ -60,8 +76,8 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); + nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { @@ -71,13 +87,13 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); if(event.type == SceneManagerEventTypeCustom) { - if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { + if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; - } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) { + } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); consumed = true; - } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) { + } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); @@ -85,9 +101,9 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv } } else if(event.type == SceneManagerEventTypeBack) { if(state == ReadMifareUlStateShowData) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID); + nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); consumed = true; } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); @@ -102,7 +118,7 @@ void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { Nfc* nfc = context; // Clean views - dialog_ex_reset(nfc->dialog_ex); + widget_reset(nfc->widget); text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c new file mode 100644 index 000000000..648aa31dc --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -0,0 +1,70 @@ +#include "../nfc_i.h" + +enum SubmenuIndex { + SubmenuIndexMfUlUnlockMenuManual, + SubmenuIndexMfUlUnlockMenuAmeebo, + SubmenuIndexMfUlUnlockMenuXiaomi, +}; + +void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + submenu_add_item( + submenu, + "Enter Password Manually", + SubmenuIndexMfUlUnlockMenuManual, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As Ameebo", + SubmenuIndexMfUlUnlockMenuAmeebo, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As Xiaomi", + SubmenuIndexMfUlUnlockMenuXiaomi, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_set_selected_item(submenu, state); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexMfUlUnlockMenuManual) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodManual; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAmeebo; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); + } + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { + Nfc* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c new file mode 100644 index 000000000..00df98e75 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -0,0 +1,45 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { + Nfc* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); + + dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); + dialog_ex_set_icon(dialog_ex, 73, 17, &I_DolphinFirstStart8_56x51); + dialog_ex_set_center_button_text(dialog_ex, "OK"); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { + Nfc* nfc = context; + + dialog_ex_reset(nfc->dialog_ex); + submenu_reset(nfc->submenu); +} diff --git a/firmware.scons b/firmware.scons index 4eb76f520..064e0ddab 100644 --- a/firmware.scons +++ b/firmware.scons @@ -97,7 +97,7 @@ else: ], ) -# Invoke child SCopscripts to populate global `env` + build their own part of the code +# Invoke child SConscripts to populate global `env` + build their own part of the code lib_targets = env.BuildModules( [ "lib", diff --git a/lib/SConscript b/lib/SConscript index 459a80d62..5e5bb2eaa 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -7,7 +7,7 @@ env.Append( "lib/drivers", "lib/flipper_format", "lib/infrared", - "lib/nfc_protocols", + "lib/nfc", "lib/one_wire", "lib/ST25RFAL002", "lib/subghz", @@ -44,7 +44,7 @@ env.Append( # fnv1a-hash # micro-ecc # microtar -# nfc_protocols +# nfc # one_wire # qrcode # u8g2 @@ -71,11 +71,11 @@ libs = env.BuildModules( "flipper_format", "infrared", "littlefs", + "mbedtls", "subghz", "nfc", "appframe", "misc", - "mbedtls", "loclass", ], ) diff --git a/lib/mbedtls.scons b/lib/mbedtls.scons index 1b0bec87d..e39d9dae8 100644 --- a/lib/mbedtls.scons +++ b/lib/mbedtls.scons @@ -11,7 +11,11 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="mbedtls") libenv.ApplyLibFlags() -sources = ["mbedtls/library/des.c", "mbedtls/library/platform_util.c"] +sources = [ + "mbedtls/library/des.c", + "mbedtls/library/sha1.c", + "mbedtls/library/platform_util.c", +] lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 649a2c5f5..9da891327 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -19,6 +19,7 @@ static const uint32_t nfc_keys_file_version = 1; // Protocols format versions static const uint32_t nfc_mifare_classic_data_format_version = 2; +static const uint32_t nfc_mifare_ultralight_data_format_version = 1; NfcDevice* nfc_device_alloc() { NfcDevice* nfc_dev = malloc(sizeof(NfcDevice)); @@ -97,6 +98,9 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) // Save Mifare Ultralight specific data do { if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break; + if(!flipper_format_write_uint32( + file, "Data format version", &nfc_mifare_ultralight_data_format_version, 1)) + break; if(!flipper_format_write_hex(file, "Signature", data->signature, sizeof(data->signature))) break; if(!flipper_format_write_hex( @@ -121,6 +125,8 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) // Write pages data uint32_t pages_total = data->data_size / 4; if(!flipper_format_write_uint32(file, "Pages total", &pages_total, 1)) break; + uint32_t pages_read = data->data_read / 4; + if(!flipper_format_write_uint32(file, "Pages read", &pages_read, 1)) break; bool pages_saved = true; for(uint16_t i = 0; i < data->data_size; i += 4) { string_printf(temp_str, "Page %d", i / 4); @@ -148,8 +154,14 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { MfUltralightData* data = &dev->dev_data.mf_ul_data; string_t temp_str; string_init(temp_str); + uint32_t data_format_version = 0; do { + // Read Mifare Ultralight format version + if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { + if(!flipper_format_rewind(file)) break; + } + // Read signature if(!flipper_format_read_hex(file, "Signature", data->signature, sizeof(data->signature))) break; @@ -173,11 +185,18 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { } if(!counters_parsed) break; // Read pages - uint32_t pages = 0; - if(!flipper_format_read_uint32(file, "Pages total", &pages, 1)) break; - data->data_size = pages * 4; + uint32_t pages_total = 0; + if(!flipper_format_read_uint32(file, "Pages total", &pages_total, 1)) break; + uint32_t pages_read = 0; + if(data_format_version < nfc_mifare_ultralight_data_format_version) { + pages_read = pages_total; + } else { + if(!flipper_format_read_uint32(file, "Pages read", &pages_read, 1)) break; + } + data->data_size = pages_total * 4; + data->data_read = pages_read * 4; bool pages_parsed = true; - for(uint16_t i = 0; i < pages; i++) { + for(uint16_t i = 0; i < pages_total; i++) { string_printf(temp_str, "Page %d", i); if(!flipper_format_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) { pages_parsed = false; @@ -1186,7 +1205,7 @@ void nfc_device_data_clear(NfcDeviceData* dev_data) { } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { memset(&dev_data->mf_classic_data, 0, sizeof(MfClassicData)); } else if(dev_data->protocol == NfcDeviceProtocolMifareUl) { - memset(&dev_data->mf_ul_data, 0, sizeof(MfUltralightData)); + mf_ul_reset(&dev_data->mf_ul_data); } else if(dev_data->protocol == NfcDeviceProtocolEMV) { memset(&dev_data->emv_data, 0, sizeof(EmvData)); } diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 7c3c083b1..a92f148a2 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -101,6 +101,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_emulate_mf_ultralight(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { nfc_worker_emulate_mf_classic(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { + nfc_worker_mf_ultralight_read_auth(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { nfc_worker_mf_classic_dict_attack(nfc_worker); } @@ -416,10 +418,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { return; } - FURI_LOG_D( - TAG, - "Start Dictionary attack, Key Count %d", - mf_classic_dict_get_total_keys(dict)); + FURI_LOG_D(TAG, "Start Dictionary attack, Key Count %d", mf_classic_dict_get_total_keys(dict)); for(size_t i = 0; i < total_sectors; i++) { FURI_LOG_I(TAG, "Sector %d", i); nfc_worker->callback(NfcWorkerEventNewSector, nfc_worker->context); @@ -462,20 +461,17 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { } } if(is_key_a_found && is_key_b_found) break; - if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) - break; + if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; } else { if(!card_removed_notified) { nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); card_removed_notified = true; card_found_notified = false; } - if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) - break; + if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; } } - if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) - break; + if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; mf_classic_read_sector(&tx_rx, data, i); mf_classic_dict_rewind(dict); } @@ -518,3 +514,57 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { rfal_platform_spi_release(); } + +void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + MfUltralightData* data = &nfc_worker->dev_data->mf_ul_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + FuriHalNfcTxRxContext tx_rx = {}; + MfUltralightReader reader = {}; + mf_ul_reset(data); + + uint32_t key = 0; + uint16_t pack = 0; + while(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) { + furi_hal_nfc_sleep(); + if(furi_hal_nfc_detect(nfc_data, 300) && nfc_data->type == FuriHalNfcTypeA) { + if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + if(data->auth_method == MfUltralightAuthMethodManual) { + nfc_worker->callback(NfcWorkerEventMfUltralightPassKey, nfc_worker->context); + key = nfc_util_bytes2num(data->auth_key, 4); + } else if(data->auth_method == MfUltralightAuthMethodAmeebo) { + key = mf_ul_pwdgen_amiibo(nfc_data); + } else if(data->auth_method == MfUltralightAuthMethodXiaomi) { + key = mf_ul_pwdgen_xiaomi(nfc_data); + } else { + FURI_LOG_E(TAG, "Incorrect auth method"); + break; + } + + data->auth_success = mf_ultralight_authenticate(&tx_rx, key, &pack); + mf_ul_read_card(&tx_rx, &reader, data); + if(data->auth_success) { + MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data); + if(config_pages != NULL) { + config_pages->auth_data.pwd.value = REVERSE_BYTES_U32(key); + config_pages->auth_data.pack.value = pack; + } + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + break; + } else { + nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context); + break; + } + } else { + nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context); + furi_delay_ms(10); + } + } else { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + furi_delay_ms(10); + } + } +} diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/nfc_worker.h index a3326808b..22cbc3dcc 100755 --- a/lib/nfc/nfc_worker.h +++ b/lib/nfc/nfc_worker.h @@ -14,6 +14,7 @@ typedef enum { NfcWorkerStateUidEmulate, NfcWorkerStateMfUltralightEmulate, NfcWorkerStateMfClassicEmulate, + NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, // Debug NfcWorkerStateEmulateApdu, @@ -44,6 +45,7 @@ typedef enum { NfcWorkerEventAborted, NfcWorkerEventCardDetected, NfcWorkerEventNoCardDetected, + NfcWorkerEventWrongCardDetected, // Mifare Classic events NfcWorkerEventNoDictFound, @@ -51,6 +53,9 @@ typedef enum { NfcWorkerEventNewDictKeyBatch, NfcWorkerEventFoundKeyA, NfcWorkerEventFoundKeyB, + + // Mifare Ultralight events + NfcWorkerEventMfUltralightPassKey, } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index bb4c31ddb..1e98879a7 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -44,4 +44,8 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker); void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker); +void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker); + +void nfc_worker_mf_ul_auth_attack(NfcWorker* nfc_worker); + void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c index 44eee8386..59482a123 100644 --- a/lib/nfc/parsers/nfc_supported_card.c +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -3,10 +3,11 @@ #include "troyka_parser.h" NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { - [NfcSupportedCardTypeTroyka] = { - .protocol = NfcDeviceProtocolMifareClassic, - .verify = troyka_parser_verify, - .read = troyka_parser_read, - .parse = troyka_parser_parse, - }, + [NfcSupportedCardTypeTroyka] = + { + .protocol = NfcDeviceProtocolMifareClassic, + .verify = troyka_parser_verify, + .read = troyka_parser_read, + .parse = troyka_parser_parse, + }, }; diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index 9dcd1d6aa..c043f2069 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -1,10 +1,39 @@ #include +#include #include "mifare_ultralight.h" +#include "nfc_util.h" #include +#include "furi_hal_nfc.h" #include #define TAG "MfUltralight" +// Algorithms from: https://github.com/RfidResearchGroup/proxmark3/blob/0f6061c16f072372b7d4d381911f1542afbc3a69/common/generator.c#L110 +uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data) { + uint8_t hash[20]; + mbedtls_sha1(data->uid, data->uid_len, hash); + + uint32_t pwd = 0; + pwd |= (hash[hash[0] % 20]) << 24; + pwd |= (hash[(hash[0] + 5) % 20]) << 16; + pwd |= (hash[(hash[0] + 13) % 20]) << 8; + pwd |= (hash[(hash[0] + 17) % 20]); + + return pwd; +} + +uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data) { + uint8_t* uid = data->uid; + + uint32_t pwd = 0; + pwd |= (uid[1] ^ uid[3] ^ 0xAA) << 24; + pwd |= (uid[2] ^ uid[4] ^ 0x55) << 16; + pwd |= (uid[3] ^ uid[5] ^ 0xAA) << 8; + pwd |= uid[4] ^ uid[6] ^ 0x55; + + return pwd; +} + bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { return true; @@ -12,6 +41,20 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { return false; } +void mf_ul_reset(MfUltralightData* data) { + furi_assert(data); + data->type = MfUltralightTypeUnknown; + memset(&data->version, 0, sizeof(MfUltralightVersion)); + memset(data->signature, 0, sizeof(data->signature)); + memset(data->counter, 0, sizeof(data->counter)); + memset(data->tearing, 0, sizeof(data->tearing)); + memset(data->data, 0, sizeof(data->data)); + data->data_size = 0; + data->data_read = 0; + data->curr_authlim = 0; + data->has_auth = false; +} + static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { switch(type) { case MfUltralightTypeUL11: @@ -127,6 +170,37 @@ bool mf_ultralight_read_version( return version_read; } +bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack) { + bool authenticated = false; + + do { + FURI_LOG_D(TAG, "Authenticating"); + tx_rx->tx_data[0] = MF_UL_AUTH; + nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]); + tx_rx->tx_bits = 40; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + FURI_LOG_D(TAG, "Tag did not respond to authentication"); + break; + } + + // PACK + if(tx_rx->rx_bits < 2 * 8) { + FURI_LOG_D(TAG, "Authentication failed"); + break; + } + + if(pack != NULL) { + *pack = (tx_rx->rx_data[0] << 8) | tx_rx->rx_data[1]; + } + + FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack); + authenticated = true; + } while(false); + + return authenticated; +} + static int16_t mf_ultralight_page_addr_to_tag_addr(uint8_t sector, uint8_t page) { return sector * 256 + page; } @@ -413,7 +487,7 @@ static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin( } } -static MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) { +MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) { if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { return (MfUltralightConfigPages*)&data->data[data->data_size - 4 * 4]; } else if( @@ -516,6 +590,7 @@ bool mf_ultralight_read_pages( tx_rx->tx_data[1] = tag_page; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) { FURI_LOG_D( TAG, @@ -524,17 +599,19 @@ bool mf_ultralight_read_pages( i + (valid_pages > 4 ? 4 : valid_pages) - 1); break; } + if(valid_pages > 4) { pages_read_cnt = 4; } else { pages_read_cnt = valid_pages; } reader->pages_read += pages_read_cnt; - data->data_size = reader->pages_read * 4; memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4); } + data->data_size = reader->pages_to_read * 4; + data->data_read = reader->pages_read * 4; - return reader->pages_read == reader->pages_to_read; + return reader->pages_read > 0; } bool mf_ultralight_fast_read_pages( @@ -620,6 +697,48 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* return counter_read == (is_single_counter ? 1 : 3); } +int16_t mf_ultralight_get_authlim( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data) { + mf_ultralight_read_version(tx_rx, reader, data); + if(!(reader->supported_features & MfUltralightSupportAuth)) { + // No authentication + return -2; + } + + uint8_t config_pages_index; + if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { + config_pages_index = reader->pages_to_read - 4; + } else if( + data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus1K) { + config_pages_index = 0xe3; + } else { + // No config pages + return -2; + } + + if(!mf_ultralight_read_pages_direct(tx_rx, config_pages_index, data->data)) { + // Config pages are not readable due to protection + return -1; + } + + MfUltralightConfigPages* config_pages = (MfUltralightConfigPages*)&data->data; + if(config_pages->auth0 >= reader->pages_to_read) { + // Authentication is not configured + return -2; + } + + int16_t authlim = config_pages->access.authlim; + if(authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus2K) { + authlim = 1 << authlim; + } + + return authlim; +} + bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { uint8_t flag_read = 0; diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 77dbd1e4e..727bffab2 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -28,6 +28,12 @@ #define MF_UL_NTAG203_COUNTER_PAGE (41) +typedef enum { + MfUltralightAuthMethodManual, + MfUltralightAuthMethodAmeebo, + MfUltralightAuthMethodXiaomi, +} MfUltralightAuthMethod; + // Important: order matters; some features are based on positioning in this enum typedef enum { MfUltralightTypeUnknown, @@ -50,6 +56,13 @@ typedef enum { MfUltralightTypeNum, } MfUltralightType; +typedef enum { + MfUltralightAuthLimitUnknown, + MfUltralightAuthLimitNotSupported, + MfUltralightAuthLimitConfigured, + MfUltralightAuthLimitNotConfigured, +} MfUltralightAuthLimit; + typedef enum { MfUltralightSupportNone = 0, MfUltralightSupportFastRead = 1 << 0, @@ -104,9 +117,14 @@ typedef struct { uint8_t signature[32]; uint32_t counter[3]; uint8_t tearing[3]; + bool has_auth; + MfUltralightAuthMethod auth_method; + uint8_t auth_key[4]; + bool auth_success; uint16_t curr_authlim; uint16_t data_size; uint8_t data[MF_UL_MAX_DUMP_SIZE]; + uint16_t data_read; } MfUltralightData; typedef struct __attribute__((packed)) { @@ -176,6 +194,8 @@ typedef struct { bool read_counter_incremented; } MfUltralightEmulator; +void mf_ul_reset(MfUltralightData* data); + bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); bool mf_ultralight_read_version( @@ -204,6 +224,10 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data); +bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack); + +MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data); + bool mf_ul_read_card( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -220,3 +244,12 @@ bool mf_ul_prepare_emulation_response( uint16_t* buff_tx_len, uint32_t* data_type, void* context); + +int16_t mf_ultralight_get_authlim( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data); + +uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data); + +uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data); From 67a9753f78d95d1158cbb09aa8548c82069dcf5b Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sun, 7 Aug 2022 18:18:39 +0300 Subject: [PATCH 02/26] Add a Mifare Classic info screen to parser output (#1504) * Add the info screen * Oops, don't dupe the points! * Show ATQA and SAK, remove the back label * And the dolphin doesn't need to be imported anymore * Correct UX to the approved one Co-authored-by: gornekich --- applications/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_classic_info.c | 72 +++++++++++++++++++ .../nfc/scenes/nfc_scene_mf_classic_menu.c | 9 +++ 3 files changed, 82 insertions(+) create mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_info.c diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 584faf309..2b5cb5cf1 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -25,6 +25,7 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_info, MfClassicInfo) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_info.c b/applications/nfc/scenes/nfc_scene_mf_classic_info.c new file mode 100644 index 000000000..b658dfa48 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_classic_info.c @@ -0,0 +1,72 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_info_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_mf_classic_info_on_enter(void* context) { + Nfc* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + MfClassicData* mf_data = &dev_data->mf_classic_data; + string_t str_tmp; + string_init(str_tmp); + + // Setup view + Widget* widget = nfc->widget; + + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type)); + widget_add_string_element( + widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); + string_printf(str_tmp, "UID:"); + for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { + string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); + } + widget_add_string_element( + widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + string_printf( + str_tmp, + "ATQA: %02X %02X SAK: %02X", + dev_data->nfc_data.atqa[0], + dev_data->nfc_data.atqa[1], + dev_data->nfc_data.sak); + widget_add_string_element( + widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); + widget_add_string_element( + widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); + widget_add_string_element( + widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); + + string_clear(str_tmp); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_mf_classic_info_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c index a5370ce77..6ee0ad868 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -3,6 +3,7 @@ enum SubmenuIndex { SubmenuIndexSave, SubmenuIndexEmulate, + SubmenuIndexInfo, }; void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { @@ -19,6 +20,9 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); + submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); @@ -43,6 +47,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_previous_scene(nfc->scene_manager); From f3d7d7dba085f4e676c1d901122fb021a3553644 Mon Sep 17 00:00:00 2001 From: Peter Seprus Date: Sun, 7 Aug 2022 17:28:04 +0200 Subject: [PATCH 03/26] Extend random name generator (#1551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extend random name generator * Format sources Co-authored-by: あく --- lib/toolbox/random_name.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/toolbox/random_name.c b/lib/toolbox/random_name.c index 4810a0675..5a5374398 100644 --- a/lib/toolbox/random_name.c +++ b/lib/toolbox/random_name.c @@ -12,15 +12,10 @@ void set_random_name(char* name, uint8_t max_name_size) { rand_generator_inited = true; } const char* prefix[] = { - "ancient", - "hollow", - "strange", - "disappeared", - "unknown", - "unthinkable", - "unnamable", - "nameless", - "my", + "ancient", "hollow", "strange", "disappeared", "unknown", + "unthinkable", "unnamable", "nameless", "my", "concealed", + "forgotten", "hidden", "mysterious", "obscure", "random", + "remote", "uncharted", "undefined", "untravelled", "untold", }; const char* suffix[] = { @@ -32,6 +27,10 @@ void set_random_name(char* name, uint8_t max_name_size) { "entree", "opening", "crack", + "access", + "corridor", + "passage", + "port", }; uint8_t prefix_i = rand() % COUNT_OF(prefix); uint8_t suffix_i = rand() % COUNT_OF(suffix); From 173c94156d4c6644046ea782eb6ac7e1b18033a4 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 7 Aug 2022 18:33:14 +0300 Subject: [PATCH 04/26] NFC: Add Skylanders support (#1553) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: add skylanders support * nfc: format sources Co-authored-by: あく --- lib/nfc/parsers/troyka_parser.c | 3 ++- lib/nfc/protocols/mifare_classic.c | 21 ++++++--------------- lib/nfc/protocols/mifare_classic.h | 2 -- lib/nfc/protocols/mifare_common.c | 3 ++- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/lib/nfc/parsers/troyka_parser.c b/lib/nfc/parsers/troyka_parser.c index 653887cb5..3167b5181 100644 --- a/lib/nfc/parsers/troyka_parser.c +++ b/lib/nfc/parsers/troyka_parser.c @@ -39,7 +39,8 @@ bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - mf_classic_get_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak, &reader); + reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + for(size_t i = 0; i < COUNT_OF(troyka_keys); i++) { mf_classic_reader_add_sector( &reader, troyka_keys[i].sector, troyka_keys[i].key_a, troyka_keys[i].key_b); diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 93fe6f694..44b783d6d 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -324,6 +324,9 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { return true; + } else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) { + //skylanders support + return true; } else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) { return true; } else { @@ -335,27 +338,15 @@ MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t S UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { return MfClassicType1k; + } else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) { + //skylanders support + return MfClassicType1k; } else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) { return MfClassicType4k; } return MfClassicType1k; } -bool mf_classic_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK, MfClassicReader* reader) { - UNUSED(ATQA1); - furi_assert(reader); - memset(reader, 0, sizeof(MfClassicReader)); - - if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { - reader->type = MfClassicType1k; - } else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) { - reader->type = MfClassicType4k; - } else { - return false; - } - return true; -} - void mf_classic_reader_add_sector( MfClassicReader* reader, uint8_t sector, diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index 85f67b118..b9921fb1c 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -82,8 +82,6 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -bool mf_classic_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK, MfClassicReader* reader); - uint8_t mf_classic_get_total_sectors_num(MfClassicType type); uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); diff --git a/lib/nfc/protocols/mifare_common.c b/lib/nfc/protocols/mifare_common.c index fd622765e..90b57e1f0 100644 --- a/lib/nfc/protocols/mifare_common.c +++ b/lib/nfc/protocols/mifare_common.c @@ -7,7 +7,8 @@ MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { type = MifareTypeUltralight; } else if( ((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) || - ((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18))) { + ((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) || + ((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01))) { type = MifareTypeClassic; } else if(ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20) { type = MifareTypeDesfire; From 81b404aafa3ead93c1496de696bef5c99b21d6fa Mon Sep 17 00:00:00 2001 From: Mayco Date: Sun, 7 Aug 2022 17:40:09 +0200 Subject: [PATCH 05/26] Add ability to type a space with the input keyboard by long-pressing "_" (#1550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mayco Co-authored-by: あく --- applications/gui/modules/text_input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/gui/modules/text_input.c b/applications/gui/modules/text_input.c index c043c3c3c..26f74e7ac 100644 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -131,7 +131,9 @@ static bool char_is_lowercase(char letter) { } static char char_to_uppercase(const char letter) { - if(isalpha(letter)) { + if(letter == '_') { + return 0x20; + } else if(isalpha(letter)) { return (letter - 0x20); } else { return letter; From 416cce9ffc9819422940978cbc66476150aec900 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sun, 7 Aug 2022 19:56:45 +0400 Subject: [PATCH 06/26] [FL-2718, FL-2719] SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER / Doitrand / Marantec / Phoenix V2 (static mode) / Phox (static mode), fix Princeton (#1516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add protocol marantec * SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER * SubGhz: add protocol Doitrand * SubGhz: delete debug * SubGhz: add protocol Phoenix V2 (static mode) * SubGhz: fix serial decode Phoenix V2 * SubGhz: fix Princeton, display serial number and button on boot * SubGhz: fix Bett decoder and fix unit_test * SubGhz: update test_random_raw for unit_test Co-authored-by: あく --- applications/unit_tests/subghz/subghz_test.c | 61 ++- assets/unit_tests/subghz/bett.sub | 7 + assets/unit_tests/subghz/bett_raw.sub | 8 + assets/unit_tests/subghz/doitrand.sub | 7 + assets/unit_tests/subghz/doitrand_raw.sub | 15 + assets/unit_tests/subghz/marantec.sub | 7 + assets/unit_tests/subghz/marantec_raw.sub | 14 + assets/unit_tests/subghz/phoenix_v2.sub | 7 + assets/unit_tests/subghz/phoenix_v2_raw.sub | 9 + assets/unit_tests/subghz/test_random_raw.sub | 20 + lib/subghz/protocols/bett.c | 357 +++++++++++++++++ lib/subghz/protocols/bett.h | 107 +++++ lib/subghz/protocols/doitrand.c | 356 +++++++++++++++++ lib/subghz/protocols/doitrand.h | 107 +++++ lib/subghz/protocols/holtek.c | 2 +- lib/subghz/protocols/marantec.c | 393 +++++++++++++++++++ lib/subghz/protocols/marantec.h | 107 +++++ lib/subghz/protocols/phoenix_v2.c | 339 ++++++++++++++++ lib/subghz/protocols/phoenix_v2.h | 107 +++++ lib/subghz/protocols/princeton.c | 25 +- lib/subghz/protocols/registry.c | 3 +- lib/subghz/protocols/registry.h | 4 + 22 files changed, 2048 insertions(+), 14 deletions(-) create mode 100644 assets/unit_tests/subghz/bett.sub create mode 100644 assets/unit_tests/subghz/bett_raw.sub create mode 100644 assets/unit_tests/subghz/doitrand.sub create mode 100644 assets/unit_tests/subghz/doitrand_raw.sub create mode 100644 assets/unit_tests/subghz/marantec.sub create mode 100644 assets/unit_tests/subghz/marantec_raw.sub create mode 100644 assets/unit_tests/subghz/phoenix_v2.sub create mode 100644 assets/unit_tests/subghz/phoenix_v2_raw.sub create mode 100644 lib/subghz/protocols/bett.c create mode 100644 lib/subghz/protocols/bett.h create mode 100644 lib/subghz/protocols/doitrand.c create mode 100644 lib/subghz/protocols/doitrand.h create mode 100644 lib/subghz/protocols/marantec.c create mode 100644 lib/subghz/protocols/marantec.h create mode 100644 lib/subghz/protocols/phoenix_v2.c create mode 100644 lib/subghz/protocols/phoenix_v2.h diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index 4799d235d..fb3c7a4eb 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 119 +#define TEST_RANDOM_COUNT_PARSE 158 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -377,6 +377,33 @@ MU_TEST(subghz_decoder_power_smart_test) { "Test decoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); } +MU_TEST(subghz_decoder_marantec_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/marantec_raw.sub"), SUBGHZ_PROTOCOL_MARANTEC_NAME), + "Test decoder " SUBGHZ_PROTOCOL_MARANTEC_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_bett_test) { + mu_assert( + subghz_decoder_test(EXT_PATH("unit_tests/subghz/bett_raw.sub"), SUBGHZ_PROTOCOL_BETT_NAME), + "Test decoder " SUBGHZ_PROTOCOL_BETT_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_doitrand_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/doitrand_raw.sub"), SUBGHZ_PROTOCOL_DOITRAND_NAME), + "Test decoder " SUBGHZ_PROTOCOL_DOITRAND_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_phoenix_v2_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/phoenix_v2_raw.sub"), SUBGHZ_PROTOCOL_PHOENIX_V2_NAME), + "Test decoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -450,6 +477,30 @@ MU_TEST(subghz_encoder_power_smart_test) { "Test encoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); } +MU_TEST(subghz_encoder_marantec_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/marantec.sub")), + "Test encoder " SUBGHZ_PROTOCOL_MARANTEC_NAME " error\r\n"); +} + +MU_TEST(subghz_encoder_bett_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/bett.sub")), + "Test encoder " SUBGHZ_PROTOCOL_BETT_NAME " error\r\n"); +} + +MU_TEST(subghz_encoder_doitrand_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/doitrand.sub")), + "Test encoder " SUBGHZ_PROTOCOL_DOITRAND_NAME " error\r\n"); +} + +MU_TEST(subghz_encoder_phoenix_v2_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/phoenix_v2.sub")), + "Test encoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -482,6 +533,10 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_secplus_v2_test); MU_RUN_TEST(subghz_decoder_holtek_test); MU_RUN_TEST(subghz_decoder_power_smart_test); + MU_RUN_TEST(subghz_decoder_marantec_test); + MU_RUN_TEST(subghz_decoder_bett_test); + MU_RUN_TEST(subghz_decoder_doitrand_test); + MU_RUN_TEST(subghz_decoder_phoenix_v2_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -495,6 +550,10 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_secplus_v1_test); MU_RUN_TEST(subghz_encoder_secplus_v2_test); MU_RUN_TEST(subghz_encoder_power_smart_test); + MU_RUN_TEST(subghz_encoder_marantec_test); + MU_RUN_TEST(subghz_encoder_bett_test); + MU_RUN_TEST(subghz_encoder_doitrand_test); + MU_RUN_TEST(subghz_encoder_phoenix_v2_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/bett.sub b/assets/unit_tests/subghz/bett.sub new file mode 100644 index 000000000..6d5dfb0d2 --- /dev/null +++ b/assets/unit_tests/subghz/bett.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: BETT +Bit: 18 +Key: 00 00 00 00 00 00 B8 B8 diff --git a/assets/unit_tests/subghz/bett_raw.sub b/assets/unit_tests/subghz/bett_raw.sub new file mode 100644 index 000000000..375723dd2 --- /dev/null +++ b/assets/unit_tests/subghz/bett_raw.sub @@ -0,0 +1,8 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: RAW +RAW_Data: 12477 16271 -64 12623 -102 40819 -98 3729 -66 14371 -66 14943 -64 5931 -66 11147 -68 74641 -102 54299 -70 18441 -66 82993 -100 66161 -68 61869 -66 6627 -66 12987 -68 30427 -68 25761 -98 6305 -66 5019 -64 30857 -132 23929 -68 25129 -39378 317 -2020 311 -2010 2033 -312 2017 -282 325 -2018 291 -2024 2035 -316 2023 -276 319 -2028 297 -2032 2029 -284 2023 -314 321 -2016 319 -2012 2003 -310 2015 -318 321 -1984 327 -16000 351 -1974 321 -2020 2041 -276 2047 -288 327 -1992 327 -2000 2055 -282 2053 -274 305 -2022 301 -2014 2049 -286 2055 -274 319 -1992 329 -2006 2065 -282 2023 -316 323 -1988 303 -16008 323 -2014 315 -1990 2053 -284 2061 -274 319 -1988 319 -2038 2033 -286 2055 -264 339 -2008 289 -2034 2035 -284 2061 -262 339 -2008 287 -2040 2037 -286 2035 -268 347 -2006 317 -15988 311 -2014 343 -2014 2027 -300 2031 -258 311 -2024 323 -2028 2023 -280 2051 -318 285 -2024 309 -2002 2039 -312 2017 -318 289 -2020 293 -2028 2035 -316 2023 -276 321 -2030 299 -15982 345 -1988 345 -2014 2029 -268 2069 -258 337 -1998 321 -2024 2025 -320 2025 -276 321 -1994 331 -2000 2057 -282 2043 -282 305 -2034 291 -2024 2039 -320 2019 -278 323 -1992 333 -15976 389 -1978 321 -1986 2069 -276 2053 -288 303 -2020 315 -1980 2067 -258 2075 -258 337 -1996 321 -2030 2027 -284 2059 -274 319 -2004 319 -2016 2033 -282 2059 -264 345 -2006 289 -16006 355 -1984 315 -2018 2033 -312 2015 -284 327 -2000 329 -2000 2063 -282 2049 -284 327 -1984 319 -2018 2035 -284 2057 -264 343 -2004 289 -2032 2059 -280 2019 -316 323 -1984 321 -15968 387 -1978 321 -1984 2069 -276 2049 -288 325 -1996 303 -2004 2055 -284 2049 -278 325 -2018 321 -1984 2075 -276 2049 -288 327 -1990 325 -1996 2031 -318 2025 -278 323 -2018 289 -16010 357 -1982 315 -2018 2035 -278 2053 -288 307 -2022 321 -2000 2049 -274 2045 -284 327 -2022 311 -2014 2033 -276 2053 -286 327 -2000 323 -2000 2061 -282 2015 -316 325 -2002 289 -15994 353 -1980 357 -1990 2035 -312 2015 -286 327 -2020 289 -2022 2033 -318 2019 -278 323 -2004 319 -2016 2059 -282 2023 -316 327 -1970 321 -2018 2059 -280 2019 -318 325 -1972 321 -15988 353 -1982 357 -1972 2071 -276 2051 -288 327 -1988 323 -1996 2061 -280 2053 -284 325 -1984 321 -2014 2031 -282 2059 -276 321 -2018 289 -2036 2031 -282 2059 -276 321 -2018 319 -15984 341 -1984 343 -2016 2029 -298 2033 -258 309 -2028 321 -2032 2035 -284 2017 -298 337 -2008 289 -2034 2027 -314 2023 -310 285 -2016 321 -2014 2035 -282 2027 -308 317 -2026 297 -15982 357 -1984 345 -1982 2067 -264 2057 -258 341 -1996 317 -2026 2057 -282 2017 -318 325 -1972 319 -2018 2059 -280 2029 -302 315 -2006 319 -2006 2059 -274 2047 -276 307 +RAW_Data: -2024 311 -15984 349 -2004 317 -2012 2029 -276 2047 -312 305 -2018 311 -2018 2037 -258 2077 -258 337 -1998 321 -2026 2031 -278 2043 -284 327 -2020 311 -2018 2031 -278 2051 -288 325 -2004 323 -15962 353 -2018 317 -2014 2007 -308 2019 -320 287 -2024 325 -1998 2035 -314 2025 -302 311 -2004 319 -2010 2027 -312 2011 -310 309 -2028 303 -2018 2027 -304 2007 -294 309 -2024 323 -16002 361 -1946 347 -2008 2027 -286 2045 -312 325 -1978 319 -2024 2043 -276 2049 -286 325 -1988 341 -1978 2061 -278 2049 -284 327 -1990 321 -2020 2029 -318 2021 -278 323 -2008 321 -15990 355 -1982 355 -1984 2031 -284 2049 -278 325 -2018 321 -2000 2047 -276 2049 -286 327 -1994 341 -1976 2067 -274 2043 -284 303 -2018 341 -1982 2061 -266 2069 -258 339 -1998 321 -16002 311 -2014 329 -2012 2027 -318 1999 -298 339 -2008 287 -2042 2031 -282 2027 -306 317 -2012 291 -2044 2037 -284 2033 -302 315 -2004 321 -2012 2037 -282 2027 -306 317 -2028 297 -15980 345 -2018 285 -2026 2037 -320 2017 -278 323 -2024 299 -2002 2069 -278 2055 -286 325 -2002 289 -2024 2037 -282 2063 -276 321 -2016 287 -2036 2025 -320 2023 -278 323 -2018 287 -16006 355 -1982 355 -1986 2033 -302 2039 -282 307 -2032 309 -2014 2043 -264 2057 -258 341 -1992 319 -2036 2033 -284 2029 -306 319 -2000 319 -2014 2035 -282 2061 -266 343 -2006 289 -16018 331 -2010 313 -2014 2021 -320 2017 -278 323 -2010 321 -2016 2037 -284 2033 -304 317 -2018 287 -2036 2037 -284 2025 -296 339 -1978 321 -2028 2057 -282 2021 -278 359 -1972 321 -15990 355 -1978 355 -1990 2035 -300 2015 -312 305 -2016 315 -2016 2053 -290 2013 -316 277 -2020 353 -1980 2059 -256 2077 -276 307 -2020 311 -2012 2047 -258 2073 -256 341 -1998 321 -15976 369 -1976 313 -2018 2051 -280 2043 -290 317 -2004 321 -2024 2023 -282 2053 -282 327 -2020 313 -2020 2035 -278 2055 -284 325 -1986 321 -2016 2033 -280 2049 -282 325 -2020 313 -15986 315 -2026 319 -2028 2003 -318 2013 -294 339 -2008 289 -2032 2027 -316 2019 -302 311 -2004 321 -2014 2033 -314 1995 -308 317 -2028 297 -2032 2035 -276 2023 -316 321 -2014 289 -15998 347 -2014 283 -2020 2035 -292 2031 -288 311 -2024 321 -2036 2001 -310 2027 -318 275 -2054 277 -2026 2029 -296 2027 -292 311 -2024 321 -2030 2031 -282 2033 -304 313 -2004 321 -15992 329 -2010 349 -1980 2037 -292 2051 -256 339 -1998 319 -2034 2029 -286 2055 -264 339 -1978 321 -2030 2027 -280 2043 -316 327 -1984 315 -2016 2063 -278 2041 -288 327 -1990 325 -15964 389 -1978 319 -1984 2063 -256 2055 -292 307 -2016 323 -2028 2027 -286 2057 -274 319 -2010 319 -2010 2033 -282 2061 -276 321 -2018 289 -2032 2027 -318 2021 -278 321 -2020 319 -15974 355 -1980 357 -2000 2035 +RAW_Data: -254 2079 -276 309 -2016 309 -2012 2035 -296 2063 -258 337 -1992 321 -2030 2037 -286 2027 -294 333 -1978 321 -2034 2029 -286 2031 -306 315 -2008 321 -15972 355 -1984 315 -2014 2037 -310 2011 -318 323 -1984 329 -2002 2033 -316 2029 -278 323 -2026 299 -2030 2035 -278 2019 -316 325 -1980 323 -2018 2053 -252 2075 -280 327 -1984 355 -15954 345 -2008 309 -2016 2045 -266 2065 -258 341 -235740 101 -202 65 -734 133 -372 401 -68 269 -236 505 -68 235 -234 875 -68 13969 -100 14297 -70 3863 -96 59337 -104 11859 -68 17409 -68 7317 -66 11443 -64 15589 -66 4381 -98 32297 -168 45445 -100 59295 -100 41417 -66 1539 -66 23001 diff --git a/assets/unit_tests/subghz/doitrand.sub b/assets/unit_tests/subghz/doitrand.sub new file mode 100644 index 000000000..ef8fb3c96 --- /dev/null +++ b/assets/unit_tests/subghz/doitrand.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Doitrand +Bit: 37 +Key: 00 00 00 1E 60 08 2F 5F diff --git a/assets/unit_tests/subghz/doitrand_raw.sub b/assets/unit_tests/subghz/doitrand_raw.sub new file mode 100644 index 000000000..a04d77ac5 --- /dev/null +++ b/assets/unit_tests/subghz/doitrand_raw.sub @@ -0,0 +1,15 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 1549 -1166 409 -1138 363 -1144 407 -1144 385 -408 1599 -1138 377 -430 1593 -1138 421 -1110 393 -1126 409 -1136 377 -1162 353 -24626 823 -1176 379 -1150 353 -1174 349 -1158 377 -454 1541 -450 1561 -1190 383 -1118 411 -398 1557 -460 1571 -450 1547 -482 1537 -450 1561 -482 1547 -470 1537 -450 1547 -482 1539 -1176 387 -422 1541 -474 1537 -448 1545 -444 1539 -450 1543 -1136 375 -414 1549 -1142 417 -1102 387 -1118 385 -1140 381 -406 1549 -1180 383 -392 1549 -1140 417 -1122 383 -1116 383 -1140 415 -1102 355 -24628 823 -1188 357 -1180 343 -1172 385 -1150 361 -440 1513 -450 1563 -1184 369 -1158 381 -448 1539 -448 1527 -482 1545 -456 1545 -450 1533 -454 1579 -450 1561 -458 1513 -450 1555 -1182 389 -390 1571 -436 1571 -418 1581 -446 1505 -456 1511 -1160 391 -390 1339 -1108 381 -1098 361 -1150 309 -1124 331 -416 1065 -1142 353 -420 1049 -1148 319 -1156 345 -1128 347 -1134 317 -1138 319 -24716 687 -1178 309 -1138 317 -1166 319 -1162 327 -408 1039 -448 1067 -1152 321 -1132 313 -436 1065 -426 1039 -442 1039 -448 1049 -418 1041 -450 1035 -426 1039 -444 1041 -418 1047 -1144 339 -402 1069 -414 1071 -422 1051 -450 1029 -424 1069 -1144 335 -418 1043 -1178 319 -1134 321 -1174 309 -1164 313 -454 1049 -1148 317 -410 1051 -1160 353 -1124 321 -1166 349 -1122 329 -1178 277 -24734 677 -1178 299 -1182 309 -1154 337 -1144 307 -430 1047 -448 1039 -1174 319 -1164 289 -452 1033 -444 1031 -450 1035 -426 1063 -412 1047 -448 1041 -446 1033 -426 1041 -438 1049 -1152 289 -438 1071 -414 1031 -448 1039 -460 1033 -414 1079 -1146 309 -428 1049 -1178 311 -1154 337 -1144 329 -1162 319 -408 1051 -1160 353 -404 1059 -1164 317 -1154 325 -1140 347 -1152 333 -1138 285 -24770 657 -1178 315 -1162 289 -1184 313 -1152 329 -446 1039 -416 1047 -1170 343 -1128 351 -418 1021 -454 1047 -416 1061 -422 1033 -454 1043 -446 1039 -416 1065 -414 1041 -424 1033 -1178 301 -450 1041 -416 1051 -452 1045 -422 1033 -454 1043 -1172 283 -436 1065 -1146 329 -1176 311 -1150 337 -1148 309 -430 1049 -1174 299 -432 1061 -1180 289 -1178 311 -1162 347 -1150 307 -1160 311 -24722 607 -1296 203 -1264 207 -1266 227 -1252 239 -498 969 -506 1013 -1214 275 -1166 289 -480 1005 -484 1003 -476 1009 -454 1009 -480 1025 -458 1003 -448 1045 -448 1009 -450 1035 -1146 321 -444 1033 -444 1029 -444 1041 -442 1041 -416 1081 -1148 343 -396 1081 -1146 345 -1120 341 -1150 345 -1120 343 -420 1077 -1146 321 -420 1053 -1152 355 -1122 321 -1162 349 -1150 297 -1178 311 -24720 523 -4340 133 -1370 99 -636 67 -1406 393 -98 397 -1320 207 -1260 225 -498 975 -522 937 -540 977 -488 973 -510 987 -490 1005 -456 1003 -476 +RAW_Data: 1015 -450 1005 -1194 289 -454 1011 -478 1009 -478 1007 -450 1033 -446 1035 -1158 353 -404 1057 -1168 309 -1162 349 -1150 309 -1158 313 -452 1047 -1146 321 -420 1059 -1152 355 -1126 319 -1160 345 -1128 353 -1152 309 -78850 165 -1196 97 -3256 65 -626 165 -130 525 -66 625 -430 891 -492 163 -792 163 -66 197 -100 595 -132 229 -15220 165 -464 97 -66 197 -264 99 -998 67 -198 195 -132 65 -296 163 -198 65 -198 691 -66 985 -134 97 -66 1485 -15420 197 -200 63 -132 97 -526 231 -64 263 -754 425 -198 97 -166 97 -132 495 -100 555 -164 391 -98 261 -98 1221 -9074 97 -2604 65 -1942 195 -590 853 -132 1225 -66 987 -1058 97 -100 131 -132 593 -98 425 -66 3965 -11360 65 -730 299 -98 99 -66 133 -232 327 -132 65 -456 163 -132 97 -196 327 -364 561 -264 1851 -234 1191 -8710 65 -596 163 -134 99 -234 97 -168 131 -496 165 -202 65 -20716 231 -68 231 -134 363 -100 133 -132 133 -198 231 -168 131 -166 99 -162 131 -196 295 -66 261 -166 955 -98 695 -66 1215 -9510 65 -3698 165 -328 65 -492 131 -66 129 -692 231 -64 163 -132 163 -98 229 -132 131 -134 97 -100 563 -15732 197 -796 165 -132 99 -562 97 -168 295 -462 99 -66 131 -332 133 -100 299 -66 329 -132 301 -68 267 -12994 299 -98 197 -228 295 -922 63 -988 65 -100 129 -164 823 -98 931 -66 331 -98 955 -9454 231 -100 163 -134 99 -796 133 -628 263 -430 67 -364 399 -98 365 -66 889 -66 5041 -4044 131 -166 265 -298 231 -98 197 -232 197 -164 163 -198 197 -98 65 -132 3525 -15068 67 -698 133 -1056 199 -2322 959 -200 297 -232 1223 -13532 65 -1650 197 -198 65 -330 129 -100 295 -164 65 -66 131 -1290 99 -134 231 -262 889 -98 231 -64 489 -66 663 -66 563 -15458 97 -362 229 -98 165 -496 131 -266 65 -98 165 -832 729 -66 133 -18682 231 -298 263 -132 363 -132 195 -132 361 -232 197 -1480 131 -164 163 -12854 65 -2522 299 -166 1357 -132 99 -98 399 -166 329 -264 395 -64 195 -196 1055 -132 1417 -14994 197 -132 459 -824 131 -428 133 -832 231 -200 65 -432 231 -100 467 -66 1151 -100 1741 -8616 97 -6904 1085 -198 261 -196 261 -232 265 -132 563 -166 65 -166 197 -100 331 -134 2009 -8664 97 -164 65 -64 263 -132 357 -64 97 -166 493 -166 165 -98 195 -130 361 -854 891 -66 365 -166 1019 -15320 97 -198 331 -166 1359 -266 229 -134 65 -100 331 -98 65 -132 265 -20774 65 -2222 97 -66 229 -132 161 -162 133 -18134 229 -198 65 -132 197 -200 263 -364 97 -100 427 -526 65 -460 131 -428 +RAW_Data: 655 -98 2625 -8562 99 -432 97 -1924 67 -632 199 -498 65 -100 1819 -132 197 -228 263 -232 133 -296 229 -66 97 -20434 199 -432 65 -764 65 -232 233 -232 133 -334 463 -232 329 -98 357 -130 131 -132 1423 -4018 133 -1984 65 -2926 99 -930 97 -430 1293 -100 531 -66 493 -100 131 -100 429 -134 465 -132 3063 -9636 67 -3696 97 -132 229 -298 131 -694 627 -132 1247 -132 297 -166 133 -66 199 -166 663 -21440 133 -400 131 -130 99 -66 531 -232 229 -134 131 -202 165 -564 131 -1258 65 -100 133 -132 299 -166 1325 -66 833 -66 1521 -9032 97 -1544 295 -98 231 -164 261 -66 131 -394 361 -296 163 -298 463 -66 195 -96 721 -13330 65 -468 99 -134 65 -4696 199 -166 659 -98 361 -198 229 -132 557 -166 625 -164 229 -66 329 -100 131 -130 263 -66 1221 -8436 329 -198 99 -66 99 -66 165 -398 65 -1326 97 -794 165 -592 131 -66 265 -266 99 -430 2421 -100 465 -100 199 -66 699 -100 65 -132 1351 -66 897 -130 1653 -15200 231 -264 195 -296 99 -328 295 -296 163 -98 129 -98 295 -264 131 -398 65 -232 97 -98 887 -132 3157 -12396 199 -134 131 -66 231 -200 267 -132 265 -500 97 -732 131 -200 165 -396 763 -166 859 -66 1391 -9164 65 -3808 165 -66 131 -1692 65 -100 1017 -330 65 -132 65 -196 685 -198 65 -198 165 -98 231 -68 99 -22854 231 -168 67 -200 65 -66 263 -100 201 -302 65 -134 65 -22948 165 -396 263 -134 131 -68 165 -862 231 -1494 1261 -66 399 -302 3089 -6572 65 -396 65 -4140 7317 -5010 7415 -15982 811 -1174 381 -1122 381 -1148 351 -1164 345 -466 1509 -482 1541 -1176 387 -1144 363 -416 1519 -478 1525 -470 1533 -460 1539 -444 1535 -460 1531 -476 1527 -448 1513 -482 1509 -1178 379 -398 1549 -444 1539 -450 1547 -446 1541 -450 1545 -1142 381 -426 1529 -1172 381 -1140 387 -1114 395 -1130 379 -438 1531 -1172 381 -398 1555 -1192 351 -1146 407 -1122 381 -1146 381 -1126 349 -24662 821 -1174 379 -1122 383 -1146 415 -1102 385 -426 1567 -432 1567 -1178 381 -1120 385 -444 1511 -482 1515 -480 1539 -452 1545 -446 1545 -486 1541 -442 1555 -456 1495 -466 1531 -1148 387 -422 1509 -466 1533 -456 1539 -470 1503 -458 1539 -1164 351 -424 1509 -1190 353 -1148 369 -1130 379 -1136 317 -404 1331 -1128 319 -406 1231 -1140 337 -1114 349 -1122 329 -1140 349 -1120 293 -24712 627 -1236 237 -1226 233 -1230 271 -1228 239 -480 1017 -452 1039 -1184 293 -1172 275 -464 1041 -444 1007 -450 1033 -448 1035 -430 1047 -450 1031 -428 1047 -444 1005 -466 1015 -1158 289 -460 1047 -430 1033 -440 1039 -442 1033 -442 1037 -1168 309 -436 1051 -1140 +RAW_Data: 343 -1158 311 -1152 347 -1120 341 -420 1041 -1178 319 -422 1051 -1150 321 -1152 345 -1126 351 -1118 345 -1158 313 -24714 689 -1170 317 -1154 323 -1138 349 -1154 301 -448 1037 -416 1083 -1150 345 -1124 313 -454 1047 -418 1031 -446 1045 -448 1037 -416 1061 -412 1043 -442 1053 -426 1039 -436 1033 -1170 309 -418 1039 -454 1049 -418 1059 -424 1049 -452 1029 -1158 319 -454 1031 -1152 353 -1152 289 -1176 311 -1162 349 -418 1051 -1148 319 -454 1027 -1152 353 -1124 319 -1162 347 -1152 333 -1144 311 -24722 685 -1138 343 -1138 329 -1162 353 -1130 325 -412 1069 -414 1085 -1150 311 -1160 311 -422 1081 -416 1031 -444 1049 -414 1071 -416 1063 -430 1037 -440 1039 -412 1049 -450 1039 -1140 351 -420 1049 -418 1065 -420 1045 -448 1041 -414 1053 -1148 345 -398 1085 -1140 315 -1166 355 -1126 319 -1158 351 -398 1071 -1140 317 -432 1071 -1138 343 -1130 339 -1144 331 -1160 319 -1162 289 -24740 693 -1130 353 -1156 319 -1136 347 -1150 301 -448 1041 -416 1063 -1178 297 -1180 311 -428 1047 -448 1037 -416 1065 -428 1037 -442 1051 -428 1039 -440 1051 -428 1037 -434 1033 -1172 311 -414 1071 -420 1049 -428 1035 -440 1069 -414 1051 -1150 343 -398 1083 -1148 345 -1120 341 -1148 347 -1122 341 -416 1071 -1148 319 -420 1061 -1152 353 -1126 321 -1158 349 -1150 297 -1176 277 -24762 631 -1238 239 -1232 271 -1230 243 -1210 271 -470 1007 -476 993 -1222 281 -1202 269 -480 1011 -454 1035 -446 1039 -446 1041 -416 1047 -450 1045 -420 1033 -454 1015 -444 1051 -1154 321 -408 1071 -414 1065 -398 1065 -440 1049 -428 1037 -1172 317 -434 1069 -1138 317 -1152 327 -1170 315 -1164 319 -410 1081 -1162 319 -404 1061 -1166 317 -1154 325 -1140 347 -1152 333 -1148 311 -24742 691 -1138 341 -1138 317 -1164 353 -1124 319 -434 1069 -412 1069 -1148 325 -1140 347 -398 1075 -414 1069 -414 1051 -452 1047 -422 1051 -416 1057 -428 1049 -450 1029 -420 1033 -1166 335 -418 1041 -416 1063 -412 1079 -412 1071 -414 1065 -1148 325 -410 1069 -1142 351 -1152 309 -1160 349 -1116 329 -436 1051 -1162 319 -426 1051 -1148 327 -1172 311 -1156 337 -1150 345 -1120 305 -83468 65 -1920 133 -98 397 -1062 199 -464 165 -728 165 -168 97 -466 497 -132 1123 -66 3163 -12612 229 -198 65 -134 363 -66 67 -132 97 -896 197 -132 199 -166 165 -166 67 -134 165 -334 365 -134 2963 -15534 231 -132 231 -168 165 -262 97 -266 65 -724 65 -166 97 -198 295 -98 131 -132 563 -100 1483 -8892 99 -954 131 -234 67 -432 1087 -98 687 -132 163 -8794 165 -6460 165 -332 331 -498 99 -200 199 -266 67 -100 131 -596 165 -332 67 -98 299 -100 265 -68 633 -100 5793 -4102 99 -198 65 -566 +RAW_Data: 65 -658 99 -132 165 -332 167 -198 99 -132 133 -2530 65 -166 795 -300 197 -366 227 -262 361 -66 2073 -20762 65 -598 231 -264 97 -592 327 -132 295 -132 297 -100 363 -68 763 -20474 63 -166 757 -200 391 -100 97 -134 131 -134 591 -98 261 -262 229 -64 195 -100 195 -100 65 -132 261 -100 919 -66 333 -13642 65 -2324 131 -130 193 -462 195 -930 865 -66 2157 -100 1923 -12176 65 -168 197 -196 131 -1250 65 -132 391 -232 659 -66 393 -100 459 -230 197 -296 3479 -12728 99 -166 131 -134 131 -366 131 -98 97 -198 263 -164 231 -2074 693 -66 597 -66 433 -98 2509 -15286 65 -198 65 -198 165 -200 461 -132 757 -16060 65 -6768 199 -98 131 -262 163 -130 197 -198 165 -398 233 -334 65 -132 131 -166 331 -134 231 -564 365 -66 265 -100 465 -66 433 -100 6915 -6612 99 -264 65 -230 63 -4800 97 -66 393 -134 65 -100 165 -100 265 -66 165 -1818 99 -230 331 -66 265 -13068 131 -100 295 -298 427 -132 131 -1530 65 -100 165 -500 165 -132 995 -68 1685 -15810 263 -130 163 -462 231 -100 233 -632 165 -528 327 -196 197 -198 1253 -100 3583 -6278 97 -788 99 -3200 65 -166 133 -438 99 -132 165 -300 329 -166 1723 -134 725 -164 133 -16880 97 -960 99 -696 65 -200 231 -132 299 -66 297 -164 131 -730 197 -23052 365 -66 99 -332 131 -166 297 -494 429 -1326 265 -132 295 -66 367 -232 263 -66 857 -15396 395 -130 229 -98 233 -132 331 -364 65 -100 529 -68 231 -830 297 -100 233 -66 8533 -5582 101 -168 67 -3968 231 -66 129 -132 163 -1154 97 -166 199 -166 233 -132 467 -134 263 -66 431 -66 363 -66 957 -100 1821 -132 497 -132 1159 -15358 397 -66 99 -98 65 -66 265 -564 65 -68 97 -166 99 -100 165 -134 297 -896 165 -330 97 -134 963 -132 4737 -7096 65 -5664 265 -266 97 -166 265 -598 65 -332 65 -66 65 -198 231 -132 329 -100 65 -17202 99 -1564 595 -98 329 -198 227 -66 459 -230 97 -1480 63 -66 131 -166 99 -166 931 -8662 133 -398 99 -134 265 -98 299 -264 233 -66 99 -100 99 -66 97 -166 199 -166 265 -234 5785 -10012 163 -2324 331 -196 331 -134 65 -100 297 -100 165 -100 131 -332 163 -302 297 -164 199 -300 199 -166 229 -68 99 -68 959 -15384 365 -134 263 -1818 229 -698 99 -232 131 -100 789 -66 491 -132 4039 -12084 99 -134 331 -796 265 -132 265 -362 167 -2310 65 -98 131 -100 525 -164 295 -15032 297 -560 197 -330 131 -196 397 -266 197 -200 263 -68 261 -496 329 -166 361 -166 1517 -66 331 -10126 97 -3736 99 -1626 131 -100 +RAW_Data: 299 -298 1025 -68 165 -66 165 -102 333 -164 4245 -8938 99 -6070 1159 -132 199 -66 265 -66 363 -266 863 -100 97 -100 2781 -11408 6995 -5040 7341 -15994 819 -1130 383 -1136 385 -1150 379 -1114 353 -432 1531 -446 1539 -1162 375 -1144 385 -394 1537 -456 1511 -450 1513 -448 1559 -442 1519 -454 1541 -446 1517 -450 1513 -476 1505 -1184 365 -410 1509 -482 1511 -478 1511 -448 1547 -444 1541 -1178 381 -414 1533 -1178 385 -1112 393 -1134 381 -1144 353 -452 1507 -1182 383 -410 1535 -1164 381 -1152 379 -1122 383 -1136 377 -1158 343 -24642 815 -1138 377 -1146 353 -1148 355 -1136 345 -428 1495 -448 1573 -1142 417 -1112 393 -416 1515 -448 1563 -450 1533 -452 1543 -448 1547 -448 1529 -466 1537 -460 1513 -450 1519 -1176 383 -398 1559 -456 1537 -460 1541 -470 1533 -450 1543 -1172 377 -426 1543 -1190 351 -1138 415 -1138 387 -1116 357 -416 1503 -1166 369 -418 1521 -1174 379 -1120 383 -1136 415 -1104 385 -1114 321 -24704 635 -1244 243 -1242 237 -1230 243 -1226 257 -492 973 -490 1007 -1204 271 -1200 273 -478 1013 -456 1011 -478 1025 -460 1003 -454 1043 -446 1039 -416 1063 -414 1041 -440 1037 -1170 309 -420 1045 -452 1049 -408 1067 -436 1051 -400 1065 -1172 317 -404 1065 -1172 317 -1158 325 -1138 341 -1158 311 -416 1075 -1152 321 -408 1083 -1126 353 -1156 321 -1138 351 -1150 331 -1144 311 -24740 659 -1174 311 -1140 329 -1162 349 -1130 327 -442 1035 -416 1063 -1148 329 -1168 315 -438 1053 -410 1049 -430 1051 -452 1029 -426 1047 -438 1059 -434 1017 -450 1037 -426 1047 -1132 321 -432 1069 -414 1067 -414 1037 -432 1053 -450 1033 -1158 319 -456 1027 -1154 353 -1120 321 -1178 317 -1152 325 -444 1037 -1174 319 -418 1053 -1148 355 -1122 319 -1160 349 -1150 331 -1144 311 -24724 631 -1238 269 -1202 269 -1224 239 -1230 257 -484 1005 -482 1007 -1204 271 -1190 309 -446 1019 -456 1003 -492 1005 -472 1007 -452 1043 -448 1013 -454 1037 -424 1041 -440 1049 -1150 321 -408 1071 -414 1033 -432 1063 -438 1049 -428 1035 -1172 317 -434 1037 -1166 311 -1164 349 -1136 315 -1172 307 -406 1083 -1138 315 -438 1051 -1150 351 -1148 319 -1156 325 -1136 345 -1130 317 -24770 675 -1162 317 -1150 343 -1130 339 -1138 317 -436 1035 -452 1041 -1172 303 -1158 349 -412 1043 -428 1049 -450 1029 -428 1049 -436 1057 -436 1051 -414 1037 -430 1049 -418 1059 -1150 319 -420 1061 -422 1031 -444 1049 -448 1039 -416 1065 -1146 329 -446 1037 -1142 351 -1152 309 -1156 349 -1116 345 -428 1053 -1140 345 -396 1079 -1148 311 -1154 341 -1148 345 -1120 341 -1150 311 -24748 633 -1238 269 -1230 225 -1238 243 -1244 257 -488 973 -482 1007 -1208 289 -1178 283 -476 1003 -478 1029 -462 1013 -444 +RAW_Data: 1035 -462 1013 -446 1035 -428 1049 -450 1031 -424 1047 -1148 309 -432 1063 -412 1041 -440 1069 -416 1049 -416 1071 -1148 321 -410 1081 -1130 355 -1120 355 -1132 343 -1130 353 -420 1053 -1150 355 -386 1065 -1156 355 -1120 345 -1132 353 -1120 345 -1160 313 -24732 705 -1144 345 -1126 351 -1152 309 -1160 313 -454 1013 -454 1051 -1166 289 -1176 311 -438 1065 -400 1065 -438 1051 -398 1067 -440 1051 -398 1063 -440 1051 -414 1043 -426 1047 -1150 343 -400 1051 -450 1015 -454 1047 -418 1057 -424 1065 -1142 339 -418 1041 -1176 319 -1160 317 -1158 317 -1154 325 -446 1037 -1176 319 -418 1053 -1150 355 -1118 321 -1176 315 -1154 325 -1172 275 -82942 97 -1816 67 -3324 65 -756 297 -100 229 -132 197 -230 165 -332 97 -66 67 -264 363 -100 131 -17052 165 -828 131 -400 133 -232 167 -132 267 -298 329 -464 67 -166 65 -1394 331 -132 265 -166 397 -132 693 -15932 97 -166 65 -100 199 -300 165 -1064 99 -298 67 -298 199 -100 997 -66 1291 -15382 131 -296 99 -364 133 -496 99 -328 363 -164 99 -16946 97 -830 65 -200 233 -132 99 -266 131 -266 397 -166 1557 -66 567 -762 231 -330 265 -10908 65 -1192 99 -698 229 -198 65 -134 99 -66 265 -98 199 -134 131 -166 167 -368 65 -264 197 -234 99 -98 165 -134 297 -66 429 -166 2215 -15050 299 -166 97 -68 263 -132 293 -462 97 -98 97 -132 65 -460 65 -198 625 -132 1493 -68 3543 -10060 65 -1958 201 -200 99 -98 67 -364 165 -66 99 -232 131 -332 97 -928 491 -100 627 -98 1151 -132 1385 -15094 163 -164 695 -66 299 -134 695 -98 99 -132 431 -234 199 -8336 97 -822 65 -628 65 -5300 199 -268 231 -66 197 -98 199 -134 165 -1062 195 -230 2117 -66 693 -15212 197 -98 259 -526 327 -198 163 -822 165 -726 131 -328 163 -22598 97 -132 65 -726 63 -164 165 -66 163 -560 131 -132 131 -198 193 -396 65 -132 65 -1022 855 -132 2663 -68 1465 -11998 67 -298 199 -132 431 -166 99 -198 199 -100 397 -16212 99 -828 65 -4854 65 -100 199 -200 561 -1460 65 -66 493 -332 629 -232 561 -66 2939 -9276 99 -5942 263 -132 65 -166 329 -164 163 -98 229 -494 129 -164 427 -98 131 -164 195 -296 65 -66 625 -100 1833 -15214 263 -362 265 -598 229 -296 65 -196 163 -98 261 -560 65 -724 199 -17234 199 -68 99 -330 97 -1188 559 -662 199 -68 165 -828 65 -100 131 -21754 261 -1618 65 -134 299 -166 133 -232 131 -66 131 -266 199 -98 99 -1092 527 -64 825 -98 1213 -15578 65 -64 165 -66 131 -398 65 -66 133 -2192 131 -396 133 -66 727 -66 295 -66 1781 -15222 229 -300 +RAW_Data: 229 -432 131 -166 133 -198 331 -100 297 -232 133 -530 199 -100 651 -66 2073 -9794 97 -2386 65 -464 99 -100 133 -364 99 -166 65 -328 197 -100 885 -134 165 -132 227 -164 855 -10348 97 -234 99 -132 265 -166 231 -102 65 -234 67 -134 133 -100 401 -66 99 -100 131 -100 297 -66 165 -132 233 -232 65 -20682 131 -362 131 -394 229 -362 559 -130 1091 -166 1195 -68 463 -66 835 -9542 263 -100 165 -100 197 -132 199 -502 131 -200 131 -68 1527 -100 265 -168 99 -66 99 -166 863 -134 231 -200 129 -166 2183 -16600 297 -164 197 -232 163 -230 229 -232 99 -196 295 -166 165 -200 231 -98 165 -428 395 -132 231 -166 1227 -5128 99 -4674 165 -328 197 -328 465 -234 199 -68 331 -98 331 -166 199 -300 3685 -18958 197 -64 163 -66 229 -228 131 -130 197 -262 131 -164 165 -766 333 -332 629 -66 759 -98 299 -3478 3113 -5094 7403 -16004 829 -1146 395 -1148 383 -1140 401 -1146 385 -422 1539 -476 1569 -1180 387 -1142 407 -400 1561 -462 1599 -448 1565 -484 1563 -472 1569 -468 1537 -482 1565 -458 1571 -444 1571 -1180 387 -420 1543 -474 1571 -488 1579 -462 1567 -444 1607 -1152 387 -452 1575 -1166 379 -1136 407 -1158 385 -1148 381 -428 1567 -1166 383 -426 1581 -1168 383 -1138 417 -1126 383 -1150 391 -1130 349 -24636 853 -1170 377 -1158 407 -1118 409 -1146 387 -422 1537 -474 1575 -1178 421 -1108 409 -400 1559 -460 1565 -444 1545 -482 1539 -450 1559 -456 1573 -444 1569 -450 1511 -448 1549 -1178 383 -402 1525 -452 1545 -450 1551 -450 1531 -466 1535 -1158 387 -392 1539 -1160 387 -1150 367 -1130 383 -1132 383 -428 1543 -1180 381 -392 1549 -1170 347 -1136 353 -1100 351 -1138 343 -1126 303 -24692 669 -1164 311 -1162 333 -1138 317 -1164 317 -420 1059 -420 1067 -1142 337 -1148 311 -430 1045 -448 1037 -414 1061 -412 1077 -410 1037 -444 1065 -414 1039 -428 1049 -408 1051 -1152 309 -440 1047 -450 1041 -414 1053 -420 1047 -454 1047 -1150 345 -398 1051 -1152 343 -1158 309 -1154 345 -1118 343 -420 1077 -1142 321 -420 1055 -1148 355 -1126 317 -1156 345 -1126 353 -1152 311 -24734 665 -1156 355 -1130 319 -1158 351 -1118 327 -416 1069 -414 1065 -1152 325 -1144 349 -398 1077 -412 1071 -412 1065 -416 1037 -428 1065 -418 1051 -448 1041 -414 1051 -420 1045 -1144 351 -414 1041 -422 1069 -418 1049 -450 1037 -416 1063 -1148 327 -448 1039 -1140 353 -1132 347 -1146 311 -1160 351 -418 1051 -1148 319 -456 1029 -1158 355 -1116 321 -1176 311 -1162 349 -1148 273 -24754 637 -1238 241 -1242 271 -1228 243 -1210 271 -470 1011 -476 993 -1224 281 -1180 289 -492 975 -492 1005 -472 1009 -448 1037 -434 1027 -466 +RAW_Data: 1043 -414 1039 -444 1041 -416 1047 -1144 349 -400 1075 -412 1037 -446 1063 -410 1041 -440 1069 -1142 313 -418 1071 -1150 355 -1128 317 -1156 351 -1124 325 -410 1071 -1140 353 -420 1047 -1152 321 -1166 319 -1146 311 -1160 351 -1118 309 -24768 691 -1140 349 -1120 345 -1122 343 -1152 345 -394 1049 -450 1041 -1140 353 -1148 317 -440 1033 -418 1051 -450 1041 -416 1049 -448 1041 -422 1067 -418 1047 -414 1039 -416 1061 -1148 345 -400 1063 -428 1037 -442 1053 -426 1039 -442 1041 -1172 311 -422 1075 -1146 319 -1156 343 -1126 353 -1134 345 -400 1063 -1148 327 -412 1073 -1140 353 -1152 311 -1158 347 -1120 345 -1122 309 -24768 579 -1302 201 -1300 173 -1278 195 -1296 203 -528 941 -538 947 -1252 277 -1196 257 -522 975 -494 999 -472 1011 -456 1007 -474 1007 -450 1037 -444 1037 -462 1001 -454 1043 -1138 315 -434 1037 -442 1041 -414 1085 -416 1071 -420 1051 -1166 319 -408 1069 -1140 353 -1120 345 -1158 347 -1142 309 -430 1051 -1142 345 -398 1081 -1148 315 -1164 355 -1130 319 -1160 351 -1122 295 -24776 667 -1146 345 -1158 311 -1150 345 -1156 311 -418 1045 -454 1049 -1150 345 -1124 351 -410 1043 -426 1069 -420 1045 -448 1039 -414 1067 -428 1035 -440 1047 -428 1035 -438 1017 -1154 321 -434 1071 -414 1065 -414 1037 -464 1017 -434 1061 -1170 315 -436 1031 -1170 317 -1154 327 -1172 311 -1156 337 -416 1043 -1178 319 -418 1055 -1150 353 -1124 319 -1160 351 -1150 297 -1176 275 -87940 229 -164 361 -68 131 -66 265 -132 133 -66 429 -132 131 -232 199 -19674 65 -2866 97 -266 97 -68 99 -232 165 -498 99 -132 67 -232 99 -862 65 -100 199 -68 65 -134 99 -166 199 -200 595 -100 365 -17268 97 -732 365 -164 397 -826 65 -166 331 -298 65 -66 297 -334 397 -66 561 -164 65 -100 265 -100 299 -98 1193 -8592 99 -6652 265 -132 131 -934 163 -134 165 -398 167 -100 829 -100 229 -11976 65 -66 329 -366 131 -430 199 -266 97 -164 65 -164 161 -526 129 -66 99 -164 65 -66 131 -130 1493 -15384 165 -398 97 -100 129 -164 131 -294 229 -264 131 -17598 133 -5180 261 -434 231 -232 65 -198 165 -66 97 -100 231 -264 263 -134 99 -430 5485 -4838 231 -100 131 -66 429 -496 65 -100 65 -166 265 -696 233 -132 231 -98 997 -98 1249 -15252 97 -1558 761 -134 99 -66 431 -164 133 -20388 65 -66 65 -530 97 -888 65 -330 97 -200 133 -330 99 -330 399 -396 231 -366 65 -428 295 -558 657 -98 165 -66 4377 -6898 97 -3848 397 -466 197 -66 65 -398 165 -200 231 -564 163 -402 67 -66 595 -132 459 -66 1085 -12238 195 -134 231 -894 231 -68 165 -698 1559 -66 361 -66 +RAW_Data: 2315 -8340 101 -498 65 -1882 267 -430 99 -498 131 -230 133 -266 165 -98 97 -266 99 -398 131 -462 99 -100 3937 -130 3803 -8272 97 -4604 229 -164 97 -164 131 -1250 361 -298 561 -166 629 -68 429 -166 363 -166 231 -98 131 -8864 65 -592 97 -3130 195 -296 65 -696 1059 -134 299 -98 995 -100 365 -100 197 -66 199 -100 2455 -12500 131 -1030 65 -3104 65 -100 263 -1520 295 -162 195 -132 527 -98 493 -66 1053 -132 163 -66 97 -196 3319 -13102 97 -100 267 -366 265 -762 197 -132 1281 -234 129 -264 165 -22650 97 -100 429 -66 163 -198 493 -264 297 -100 1295 -66 131 -66 395 -132 1697 -66 5577 -10084 65 -1894 67 -132 131 -264 259 -132 365 -98 263 -164 201 -166 199 -200 299 -132 165 -134 231 -166 131 -132 1291 -98 65 -98 661 -8376 65 -296 263 -232 165 -166 327 -494 65 -100 65 -66 263 -98 195 -98 65 -22842 99 -132 65 -464 361 -296 99 -130 195 -296 163 -132 97 -460 65 -132 163 -856 1327 -66 265 -15278 131 -468 99 -100 65 -464 97 -200 199 -130 65 -134 133 -164 297 -1390 499 -166 919 -13096 197 -4346 97 -196 97 -262 97 -330 97 -528 133 -198 131 -166 197 -962 65 -98 299 -98 99 -200 1665 -16846 65 -2444 165 -564 397 -498 65 -100 163 -66 365 -66 297 -364 65 -266 65 -134 165 -17172 67 -300 131 -262 99 -166 231 -726 197 -130 689 -200 97 -132 65 -396 97 -98 99 -98 229 -398 163 -168 263 -528 1019 -66 467 -100 533 -15150 97 -500 331 -198 67 -100 131 -566 99 -66 331 -100 197 -366 99 -898 1057 -66 863 -132 757 -66 559 -8454 99 -1196 97 -3724 131 -130 131 -264 97 -594 363 -1060 99 -100 165 -362 163 -460 195 -98 129 -922 99 -328 691 -66 5965 -12210 131 -132 65 -98 263 -164 65 -230 97 -230 163 -532 97 -394 263 -362 65 -98 163 -426 65 -100 1213 -100 495 -164 461 -8616 129 -3792 133 -132 265 -132 131 -100 161 -132 359 -196 361 -790 63 -164 1889 -15496 165 -66 265 -300 299 -334 297 -298 131 -132 97 -100 99 -232 65 -300 65 -132 233 -564 431 -66 533 -98 1459 -9390 97 -3462 231 -266 163 -202 131 -166 301 -66 465 -66 799 -200 199 -266 427 -132 799 -66 4333 -13748 65 -1298 165 -234 133 -168 165 -696 329 -956 327 -166 163 -98 263 -426 1247 -132 3303 -10574 65 -428 263 -832 199 -498 65 -200 165 -924 851 -66 393 -66 563 -134 2149 -66 1291 -10298 67 -1264 7383 -5036 7419 -15962 823 -1198 347 -1188 349 -1150 373 -1186 349 -442 1543 -452 1579 -1148 381 -1168 347 -458 1535 -458 1577 -444 1577 -486 diff --git a/assets/unit_tests/subghz/marantec.sub b/assets/unit_tests/subghz/marantec.sub new file mode 100644 index 000000000..80f1b0531 --- /dev/null +++ b/assets/unit_tests/subghz/marantec.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Marantec +Bit: 49 +Key: 00 01 30 07 10 DF 86 9F diff --git a/assets/unit_tests/subghz/marantec_raw.sub b/assets/unit_tests/subghz/marantec_raw.sub new file mode 100644 index 000000000..f4c2d6d40 --- /dev/null +++ b/assets/unit_tests/subghz/marantec_raw.sub @@ -0,0 +1,14 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 3487 -68 18413 -66 6689 -17938 65 -68 495 -98 1129 -860 697 -166 395 -100 463 -100 163 -14692 263 -794 65 -64 99 -2922 131 -200 97 -168 99 -100 199 -962 495 -68 165 -98 299 -198 133 -168 3917 -98 963 -132 461 -100 1089 -166 331 -134 633 -164 201 -100 363 -164 335 -200 265 -68 531 -166 699 -132 529 -166 397 -98 895 -168 65 -100 399 -366 463 -66 197 -134 431 -66 163 -98 623 -166 301 -98 263 -98 263 -66 197 -98 329 -98 525 -66 331 -200 1025 -66 629 -132 763 -166 233 -66 431 -132 133 -100 429 -264 165 -132 299 -166 429 -68 4605 -134 593 -134 4917 -60834 167 -10282 1941 -1122 865 -2086 921 -1072 1921 -1042 939 -1056 945 -1044 939 -1052 945 -1024 971 -1024 973 -1002 969 -1010 989 -1996 1007 -994 979 -1014 1965 -1014 977 -1020 969 -2004 1993 -982 1011 -982 1005 -984 977 -2008 981 -1006 1993 -1966 999 -994 1007 -982 1005 -984 1007 -996 975 -1016 1987 -996 973 -1016 969 -1004 1013 -1970 1011 -984 1999 -1970 1995 -984 1021 -1968 1005 -994 1003 -970 999 -984 1023 -974 1015 -8920 1995 -1014 1001 -1966 1013 -986 1991 -986 1007 -996 973 -1012 999 -978 985 -1006 1005 -984 997 -978 1015 -1000 973 -1982 1025 -982 985 -1008 1973 -1004 1007 -982 983 -1998 2009 -972 1009 -980 999 -978 1011 -1970 1011 -986 1999 -1978 1007 -988 1007 -994 975 -1012 1003 -972 1009 -978 1987 -986 1007 -982 1017 -994 971 -1990 1009 -984 1997 -1978 1999 -1010 993 -1964 1005 -1000 1007 -980 997 -984 1017 -972 999 -8932 2031 -980 989 -1988 985 -1016 1983 -986 1007 -994 975 -1016 975 -998 977 -1012 999 -982 985 -1006 983 -1018 993 -1968 1017 -996 975 -1016 1965 -1012 979 -1018 971 -2004 1991 -978 1003 -984 1015 -992 973 -2004 1005 -976 1991 -2008 975 -986 1005 -998 977 -1012 999 -978 985 -1010 1973 -1004 1013 -980 981 -1004 1007 -1996 975 -986 1993 -2006 1961 -1002 1013 -1974 985 -1008 1011 -978 997 -1006 981 -1012 991 -8918 8005 -3924 1887 -174620 131 -3974 131 -298 559 -230 65 -132 265 -98 863 -168 333 -66 299 -234 463 -166 331 -102 697 -200 199 -98 265 -100 663 -166 331 -66 599 -132 99 -66 1261 -66 399 -100 265 -100 1199 -66 265 -166 101 -66 599 -232 197 -100 561 -66 499 -132 797 -132 427 -66 265 -298 465 -66 565 -198 97 -100 695 -100 531 -132 267 -66 429 -98 231 -100 331 -100 333 -98 363 -198 67 -100 165 -100 231 -100 729 -134 1061 -100 493 -164 665 -132 259 -128 257 -130 329 -98 361 -66 263 -100 227 -66 491 -98 295 -166 229 -132 229 -130 263 -130 233 -100 331 -232 99 -100 165 -66 667 -164 795 -66 695 -68 429 -132 +RAW_Data: 559 -66 16863 -66 19215 -12276 65 -2086 131 -2188 65 -132 67 -166 299 -364 65 -100 131 -468 233 -200 497 -498 297 -100 363 -198 329 -130 327 -164 229 -64 427 -164 657 -132 829 -532 895 -66 297 -130 425 -166 363 -132 329 -100 465 -100 465 -198 65 -262 429 -98 495 -100 295 -528 131 -132 1129 -134 259 -130 327 -100 397 -66 261 -230 99 -66 229 -132 625 -68 131 -100 587 -66 329 -64 293 -130 1741 -132 325 -132 197 -98 261 -98 99 -132 561 -166 165 -66 391 -66 329 -98 231 -132 465 -100 331 -300 199 -132 299 -132 165 -164 229 -98 565 -100 395 -132 131 -100 327 -130 97 -98 163 -132 293 -98 557 -66 199 -166 233 -132 265 -166 627 -100 265 -132 595 -166 99 -98 199 -100 267 -166 795 -166 265 -166 297 -66 131 -166 331 -134 793 -164 263 -198 299 -100 265 -166 257 -100 197 -198 599 -132 333 -66 265 -100 229 -100 165 -204 465 -166 97 -232 365 -166 431 -68 199 -166 99 -236 365 -132 1297 -66 1361 -100 989 -98 297 -132 12467 -232 361 -100 263 -132 261 -196 229 -296 65 -66 329 -164 229 -164 263 -66 563 -232 3415 -132 11115 -100 97 -100 363 -164 99 -66 199 -100 99 -66 561 -164 259 -168 233 -132 333 -166 567 -98 297 -66 399 -66 399 -298 327 -132 685 -98 393 -98 819 -100 231 -270 429 -68 461 -132 131 -134 1121 -230 787 -132 1393 -132 233 -100 331 -66 497 -166 563 -196 425 -98 525 -66 723 -98 265 -134 365 -66 1297 -166 433 -98 165 -134 231 -134 263 -100 369 -198 99 -100 631 -634 331 -132 565 -132 265 -102 267 -98 467 -200 297 -130 731 -100 367 -98 229 -130 99 -98 263 -164 493 -100 297 -198 429 -66 425 -66 1021 -164 295 -198 97 -198 263 -132 425 -98 493 -98 197 -98 593 -264 65 -294 197 -66 295 -66 561 -196 565 -166 2675 -132 19393 -134 5403 -164 369 -166 467 -132 361 -526 395 -66 361 -132 529 -66 431 -66 465 -166 363 -98 65 -98 229 -98 359 -100 197 -132 201 -100 467 -166 397 -100 297 -130 229 -98 361 -98 199 -130 297 -66 659 -132 261 -98 819 -98 393 -132 329 -132 557 -132 163 -130 657 -66 295 -134 1189 -100 399 -102 861 -100 369 -132 331 -134 263 -666 65 -134 427 -64 197 -98 559 -68 297 -98 493 -164 197 -164 525 -66 131 -98 493 -66 595 -100 233 -100 265 -132 65 -66 465 -266 527 -98 855 -132 493 -66 393 -298 331 -100 131 -66 859 -198 495 -100 265 -98 367 -66 727 -196 535 -66 263 -66 397 -332 65 -198 331 -134 297 -330 +RAW_Data: 261 -100 3291 -68 2553 -19050 1855 -100 1259 -200 165 -100 39479 -100 233 -68 1027 -166 595 -66 231 -168 199 -98 265 -232 563 -166 795 -98 99 -460 65 -362 1017 -98 229 -98 625 -66 231 -98 161 -196 363 -98 363 -100 631 -132 297 -66 333 -300 99 -66 295 -230 985 -100 623 -132 1319 -100 65 -68 231 -232 197 -232 331 -100 199 -168 567 -166 133 -232 823 -396 327 -132 855 -232 165 -100 401 -166 599 -198 167 -132 299 -198 663 -132 165 -134 67 -66 1687 -66 1705 -100 265 -232 297 -100 531 -66 333 -100 1263 -66 297 -164 299 -98 431 -398 97 -66 199 -296 231 -232 925 -100 131 -132 229 -164 361 -66 267 -166 197 -100 491 -132 261 -132 1183 -98 891 -100 265 -100 99 -100 725 -100 303 -60886 131 -10310 1911 -1226 749 -2146 899 -1084 1905 -1070 917 -1044 973 -1042 927 -1050 949 -1044 965 -1012 949 -1046 965 -1014 977 -2008 981 -980 995 -1012 1969 -1018 971 -1014 975 -2014 1967 -1016 971 -1014 977 -984 1003 -2006 973 -1000 2001 -1978 1013 -980 1001 -972 1009 -978 991 -1010 983 -1004 1989 -1012 983 -978 995 -1014 983 -2002 977 -984 2023 -1968 1997 -986 999 -1970 1003 -1000 1009 -978 1017 -974 1009 -978 1001 -8948 1975 -1016 973 -2004 999 -978 2001 -986 1001 -978 1009 -986 1001 -1010 975 -998 1011 -992 975 -982 1005 -1000 1009 -1970 1011 -982 1009 -984 2003 -978 1001 -976 1015 -1966 1999 -1010 989 -982 989 -1004 1001 -1978 1013 -978 2005 -1966 1019 -972 1011 -980 997 -976 1011 -1004 999 -966 1997 -1000 999 -1002 975 -986 999 -1994 1007 -980 1993 -1978 2001 -1008 991 -1970 1009 -998 975 -1016 971 -1006 1013 -980 1001 -8922 2001 -994 1009 -1972 997 -1012 1971 -984 1005 -1012 977 -998 1009 -978 1011 -984 977 -1012 979 -1016 977 -1010 977 -2010 981 -1006 971 -1020 1985 -984 1005 -978 999 -1990 1997 -980 997 -1010 981 -1014 989 -1976 1005 -966 1995 -1998 997 -982 1021 -972 1003 -986 997 -1012 975 -982 1995 -1014 999 -980 983 -1004 1003 -1976 1007 -980 1983 -2012 1983 -998 977 -2010 973 -1014 973 -1018 973 -1014 975 -1016 971 -8956 7999 -3926 1865 -177334 165 -166 199 -496 431 -66 1319 -132 297 -164 457 -68 231 -100 863 -98 603 -100 663 -100 789 -262 491 -166 729 -100 795 -364 365 -132 293 -100 197 -98 625 -200 231 -132 229 -132 227 -100 755 -526 329 -134 793 -100 167 -200 335 -66 65 -134 265 -66 201 -66 1023 -100 63 -21396 133 -198 65 -66 263 -98 393 -134 65 -66 329 -68 199 -432 263 -394 131 -130 195 -66 687 -66 295 -164 229 -196 97 -98 559 -98 1283 -98 531 -66 331 -68 435 -100 393 -628 431 -132 99 -66 +RAW_Data: 329 -66 2519 -100 6759 -12690 463 -232 97 -3252 65 -2592 65 -132 99 -198 67 -496 99 -300 231 -132 233 -66 165 -132 131 -164 201 -66 4113 -66 1987 -68 15385 -98 8199 -16614 165 -1258 495 -1354 229 -166 297 -134 3653 -100 12533 -66 3759 -162 591 -132 361 -130 527 -100 327 -200 65 -66 461 -132 327 -132 461 -100 559 -198 263 -132 161 -98 329 -132 327 -68 395 -66 165 -132 163 -196 261 -66 361 -98 229 -132 301 -134 761 -66 399 -166 99 -66 461 -98 857 -98 131 -262 359 -132 199 -100 299 -166 363 -132 297 -132 199 -132 265 -166 133 -100 301 -268 463 -98 231 -134 265 -98 527 -298 265 -136 531 -132 363 -132 129 -130 527 -132 297 -66 297 -68 397 -466 99 -132 697 -98 233 -464 131 -132 365 -134 465 -98 635 -98 299 -66 497 -132 197 -132 489 -166 327 -98 1151 -130 295 -132 623 -164 97 -68 297 -100 1293 -100 1759 -66 1259 -132 729 -100 797 -66 99 -66 231 -98 529 -166 331 -166 299 -202 431 -134 467 -462 329 -462 1051 -98 625 -66 195 -100 461 -196 429 -132 197 -66 129 -66 229 -166 589 -164 629 -66 1053 -166 231 -98 263 -132 329 -132 267 -132 427 -130 65 -130 229 -166 4121 -66 15899 -19980 495 -264 165 -432 65 -132 65 -662 663 -100 793 -66 723 -164 565 -100 363 -166 199 -98 465 -100 299 -168 265 -198 695 -132 131 -268 497 -66 265 -134 199 -98 231 -134 499 -100 989 -132 429 -196 327 -132 131 -164 427 -66 263 -66 525 -132 1091 -100 793 -132 491 -66 195 -526 921 -134 363 -98 693 -230 165 -98 1711 -132 293 -66 659 -196 231 -66 261 -66 163 -66 1349 -166 363 -100 65 -100 299 -100 393 -66 495 -134 229 -98 131 -98 463 -362 361 -132 231 -66 491 -396 361 -132 97 -66 163 -198 229 -294 229 -198 165 -164 65 -100 623 -66 195 -98 261 -130 65 -98 563 -66 267 -166 1057 -632 531 -132 463 -100 663 -166 133 -100 569 -164 197 -66 431 -164 261 -132 363 -100 427 -164 263 -198 623 -66 589 -166 133 -166 199 -66 199 -268 65 -98 427 -66 163 -132 563 -198 363 -166 397 -98 1025 -66 197 -66 163 -132 693 -164 195 -66 427 -100 131 -66 433 -132 199 -402 231 -66 335 -100 993 -100 463 -232 65 -100 65 -66 7165 -66 6785 -66 895 -66 923 -198 97 -164 689 -166 361 -198 99 -66 753 -498 365 -66 567 -232 397 -66 199 -132 233 -200 995 -296 365 -166 597 -100 199 -134 99 -166 197 -332 431 -166 331 -66 199 -100 431 -232 493 -166 457 -98 231 -132 427 -230 559 -98 +RAW_Data: 261 -132 1051 -66 7501 -98 22107 -19232 2271 -166 133 -60834 165 -10284 595 -5446 885 -1106 1891 -1088 897 -1068 949 -1050 929 -1040 947 -1048 959 -1008 985 -1008 973 -1012 993 -2004 979 -998 975 -1014 1987 -998 977 -1014 971 -1998 2007 -974 1013 -976 999 -982 1023 -1962 1005 -1000 1969 -2010 977 -1016 971 -1004 1009 -980 985 -1002 979 -1014 1977 -1012 979 -1016 971 -1012 977 -1986 1021 -974 2005 -1968 2007 -976 1011 -1966 1009 -984 1009 -984 985 -1020 969 -1002 997 -8952 1995 -986 1017 -1988 989 -976 1979 -1028 975 -988 1009 -986 1007 -992 973 -1014 1001 -974 1011 -978 995 -1006 979 -2004 975 -1022 973 -984 1999 -1014 977 -984 1003 -2004 1995 -976 1005 -998 999 -982 981 -2002 983 -986 1989 -1998 1009 -976 999 -1010 991 -978 1013 -968 1011 -986 1995 -982 1023 -974 981 -1020 993 -1970 1007 -996 1995 -1982 1999 -986 993 -2002 985 -998 975 -1014 969 -1004 1009 -978 997 -8962 1989 -990 1009 -1954 1025 -984 2007 -962 1011 -980 1001 -982 1009 -1002 1007 -980 1005 -976 1007 -980 997 -976 1009 -2002 977 -988 1005 -982 2001 -976 1009 -988 1005 -1968 2029 -974 1003 -990 1011 -958 1005 -1972 1039 -978 1999 -1978 1009 -954 1037 -978 1007 -954 1039 -980 1011 -958 1999 -974 1031 -990 993 -972 1011 -1980 1011 -978 2009 -1968 1993 -982 1003 -1974 1007 -1006 1001 -986 985 -986 1001 -982 1033 -8924 8013 -3924 1851 -170400 493 -132 131 -164 65 -724 461 -164 693 -100 265 -100 229 -100 199 -98 363 -232 363 -100 131 -68 531 -166 165 -134 265 -66 727 -300 131 -198 99 -132 99 -134 597 -102 295 -130 131 -230 129 -98 689 -264 263 -134 231 -134 199 -132 131 -68 295 -100 163 -130 591 -98 327 -164 231 -66 589 -98 2077 -134 1389 -66 2913 -66 3045 -66 4463 -98 391 -132 489 -164 295 -66 523 -166 329 -98 195 -98 165 -100 165 -66 231 -100 895 -98 265 -132 595 -132 297 -494 261 -198 331 -100 131 -134 429 -68 231 -298 1193 -66 99 -100 627 -132 331 -98 393 -98 657 -132 163 -392 359 -132 163 -64 655 -164 263 -64 531 -98 265 -164 499 -100 229 -64 459 -100 199 -66 165 -130 197 -132 393 -66 163 -228 229 -132 65 -132 263 -100 357 -98 991 -328 595 -132 197 -130 759 -66 131 -166 267 -100 1251 -64 361 -66 395 -954 559 -132 295 -98 327 -100 295 -100 367 -198 391 -298 363 -132 495 -132 523 -66 97 -132 763 -198 131 -66 197 -100 525 -130 1059 -64 461 -166 563 -134 331 -66 463 -134 329 -198 199 -166 265 -266 1061 -66 331 -366 65 -66 1225 -100 299 -66 299 -132 133 -298 265 -100 1129 -364 163 -460 297 -132 297 -100 299 -100 +RAW_Data: 529 -166 2423 -100 199 -66 22473 -20988 131 -100 395 -166 165 -268 133 -100 17947 -68 8295 -132 267 -66 295 -100 627 -98 199 -200 597 -168 363 -266 365 -68 597 -66 431 -166 233 -98 465 -100 533 -132 299 -66 533 -66 361 -98 229 -98 459 -132 129 -232 63 -66 427 -132 395 -98 361 -98 359 -100 131 -134 1721 -66 431 -132 67 -398 395 -100 361 -66 1693 -230 1381 -98 1879 -100 693 -66 299 -100 233 -132 133 -134 2807 -132 5113 -66 1317 -68 5575 -98 199 -168 235 -432 463 -100 1679 -66 6115 -134 10653 -19120 97 -426 99 -162 99 -64 263 -166 227 -132 727 -100 99 -98 1163 -66 497 -132 197 -66 293 -98 789 -66 1051 -66 395 -64 293 -132 983 -66 1225 -66 65 -168 99 -100 299 -164 491 -166 365 -132 265 -100 397 -132 99 -100 265 -234 299 -100 233 -100 433 -232 363 -66 197 -130 789 -164 525 -132 331 -132 199 -66 195 -66 459 -98 163 -66 197 -164 229 -132 261 -130 65 -98 361 -64 625 -66 591 -66 863 -198 465 -132 631 -66 699 -100 131 -100 197 -166 535 -66 131 -100 297 -132 499 -66 599 -266 295 -132 359 -66 197 -196 263 -132 99 -98 261 -164 163 -66 493 -132 433 -134 495 -98 197 -132 391 -230 393 -66 263 -66 425 -66 261 -66 427 -200 397 -198 97 -132 99 -132 959 -100 13369 -66 1227 -100 295 -164 263 -232 261 -196 393 -230 227 -132 297 -100 97 -100 195 -262 893 -66 725 -66 331 -100 267 -134 1091 -132 133 -166 265 -100 461 -200 729 -100 431 -98 1093 -66 197 -168 265 -100 663 -98 363 -132 97 -132 523 -328 693 -98 397 -396 229 -164 491 -66 131 -132 591 -66 197 -66 823 -66 331 -66 459 -394 97 -100 529 -98 199 -100 563 -132 461 -166 231 -596 163 -132 687 -164 165 -164 165 -132 265 -68 563 -66 131 -66 233 -166 657 -166 395 -100 1147 -66 229 -132 199 -236 65 -66 263 -66 233 -66 235 -66 199 -266 561 -166 133 -166 199 -132 731 -100 363 -198 227 -132 261 -166 657 -98 459 -98 393 -100 229 -100 229 -130 297 -98 233 -98 463 -200 401 -64 99 -132 199 -132 131 -68 629 -66 265 -66 163 -100 529 -66 297 -166 299 -132 233 -100 199 -134 763 -66 297 -100 865 -236 99 -66 265 -432 265 -198 295 -68 463 -198 365 -166 131 -68 197 -168 731 -68 1293 -168 365 -132 725 -66 199 -64 627 -66 299 -134 231 -264 2051 -98 131 -66 425 -66 391 -100 163 -132 97 -132 523 -164 129 -162 427 -66 231 -100 335 -166 1423 -600 789 -164 165 -66 329 -262 691 -132 +RAW_Data: 197 -162 4471 -64 9599 -60872 143 -10288 613 -890 131 -166 97 -4144 867 -1130 1871 -1104 897 -1048 941 -1076 933 -1048 941 -1046 939 -1048 943 -1012 973 -1048 945 -2002 987 -1008 985 -1014 1983 -984 1005 -998 975 -2008 1999 -978 1001 -978 1011 -976 997 -1984 1009 -990 1997 -1966 1005 -1000 977 -1012 999 -984 983 -1006 999 -988 1989 -982 1007 -1000 973 -1002 1019 -1966 1015 -986 1989 -1980 1991 -984 1009 -1990 985 -982 1021 -972 999 -996 1011 -980 1003 -8954 1991 -992 1007 -1972 1009 -978 2003 -982 985 -978 1019 -986 1019 -970 1015 -958 1025 -974 1011 -990 997 -978 1013 -1980 1007 -978 1019 -976 1995 -972 1007 -976 1009 -1994 2009 -952 1007 -1010 1011 -952 1005 -2000 1003 -974 2003 -1982 1007 -976 999 -978 1009 -978 1023 -986 1017 -972 2011 -972 1009 -978 1001 -974 1011 -1964 1015 -982 2023 -1950 1999 -988 1025 -1964 1021 -958 1005 -982 1029 -984 981 -1004 1001 -8932 1999 -986 1015 -1982 1001 -986 1991 -984 1007 -994 973 -1016 971 -1006 1011 -980 985 -1004 979 -1014 983 -1004 977 -2006 1005 -984 973 -1018 1969 -1016 969 -1006 1013 -1972 1999 -974 999 -1006 997 -974 1003 -2010 977 -1002 1991 -1970 1011 -1002 971 -1014 973 -1016 973 -1014 975 -1016 1995 -980 999 -976 1013 -978 995 -2006 975 -1018 1969 -2008 1967 -1014 969 -1990 1001 -1018 973 -1014 975 -986 1001 -1008 969 -8960 8009 -3874 1797 -165864 327 -132 955 -130 557 -100 229 -98 263 -66 129 -66 461 -198 265 -134 559 -100 165 -266 263 -166 529 -132 327 -130 65 -196 395 -100 165 -98 327 -66 395 -130 521 -66 693 -66 331 -66 365 -132 499 -66 331 -66 231 -164 659 -66 493 -198 263 -98 131 -100 695 -100 133 -98 431 -100 333 -234 265 -166 165 -68 729 -66 99 -66 459 -98 197 -98 327 -100 295 -166 231 -132 299 -66 331 -66 199 -132 197 -100 663 -98 461 -68 329 -196 295 -98 393 -100 459 -100 1701 -98 13057 -100 395 -66 397 -100 663 -100 563 -100 131 -66 331 -100 297 -100 593 -164 701 -66 297 -66 365 -66 331 -98 459 -130 361 -132 495 -264 331 -66 329 -64 165 -66 329 -266 331 -164 301 -266 97 -68 529 -66 233 -132 431 -132 231 -68 267 -66 199 -66 599 -134 65 -100 197 -66 1317 -98 165 -132 523 -130 131 -100 295 -460 65 -164 623 -164 293 -132 331 -166 1051 -130 227 -230 329 -134 265 -66 827 -98 525 -132 97 -66 497 -66 1097 -100 595 -66 99 -166 495 -66 525 -132 327 -100 329 -66 331 -68 263 -436 65 -100 929 -168 465 -266 731 -100 261 -66 525 -66 65 -66 295 -132 591 -98 623 -100 231 -166 231 -396 97 -66 565 -66 499 -100 +RAW_Data: 231 -66 363 -66 2355 -16412 431 -66 1061 -926 99 -594 229 -528 97 -68 501 -100 197 -100 67 -166 22923 -64 3651 -66 25605 -100 23205 -68 10819 -98 327 -164 195 -132 425 -166 231 -134 597 -200 131 -68 431 -66 331 -132 329 -66 301 -100 297 -100 233 -132 529 -66 561 -232 395 -98 295 -98 521 -66 329 -166 467 -200 231 -364 99 -100 299 -198 395 -98 625 -68 131 -98 229 -98 295 -98 329 -98 557 -98 131 -66 491 -134 65 -100 233 -200 365 -232 459 -198 759 -98 165 -100 297 -134 431 -66 397 -134 195 -166 597 -66 1755 -66 955 -132 361 -132 293 -98 65 -66 197 -298 231 -100 559 -98 427 -132 655 -66 6771 -66 8835 -66 567 -68 625 -66 663 -100 493 -130 725 -66 63 -100 263 -134 299 -364 429 -100 395 -100 163 -100 297 -100 199 -66 531 -98 497 -132 595 -132 363 -66 261 -198 395 -130 425 -198 131 -166 429 -264 397 -166 727 -66 725 -132 361 -164 721 -132 195 -134 1151 -132 397 -98 21075 -134 267 -200 1097 -98 297 -100 725 -132 265 -200 597 -66 333 -198 97 -598 197 -66 233 -134 297 -234 659 -64 165 -66 227 -98 197 -100 327 -130 559 -98 991 -100 263 -130 229 -132 359 -100 325 -132 263 -100 399 -98 963 -132 431 -66 761 -68 723 -66 395 -130 493 -100 165 -66 297 -334 97 -132 787 -100 491 -232 949 -100 431 -232 99 -132 233 -164 299 -100 329 -64 233 -100 333 -66 365 -66 661 -200 393 -134 263 -102 297 -132 467 -66 493 -100 631 -66 265 -68 331 -100 295 -162 163 -164 395 -66 697 -66 663 -134 463 -168 65 -66 963 -66 265 -132 199 -134 723 -100 821 -66 163 -130 457 -362 97 -66 461 -98 563 -66 725 -132 727 -100 661 -66 1231 -100 231 -366 2455 -98 689 -132 635 -132 99 -166 729 -66 233 -100 465 -132 561 -168 697 -200 295 -298 65 -198 131 -66 329 -66 231 -134 465 -166 265 -132 299 -200 825 -66 361 -66 129 -198 667 -98 1021 -66 697 -100 397 -68 265 -100 429 -234 99 -98 953 -98 985 -166 293 -66 263 -66 131 -132 295 -66 723 -66 497 -66 265 -166 565 -68 465 -132 65 -66 531 -132 597 -166 331 -66 299 -66 65 -100 1461 -100 463 -66 293 -328 133 -132 499 -66 263 -100 167 -198 267 -66 993 -100 327 -98 493 -164 97 -98 263 -100 427 -66 229 -64 261 -98 325 -100 361 -66 393 -132 595 -164 363 -164 163 -66 131 -134 231 -66 731 -66 1025 -100 563 -134 131 -66 229 -134 233 -100 693 -100 299 -166 299 -134 693 -66 359 -166 499 -100 +RAW_Data: 231 -100 23109 -60820 133 -10320 631 -5396 883 -1106 1887 -1072 943 -1040 957 -1012 987 -1010 957 -1012 983 -1002 999 -1012 977 -984 1003 -2002 999 -978 983 -1010 1977 -1002 1007 -968 999 -1996 1999 -986 995 -1012 977 -984 1001 -2000 999 -982 1979 -2010 983 -1010 989 -978 991 -1012 985 -982 1021 -976 1979 -1006 1013 -982 997 -976 1019 -1968 1005 -1000 1965 -2014 1967 -1016 993 -1970 1005 -998 973 -1014 999 -974 1011 -976 995 -8958 2009 -984 1007 -1968 997 -1008 1965 -994 1009 -984 1007 -986 1011 -962 1009 -984 1009 -1002 1007 -978 1003 -976 1009 -1970 1011 -982 1009 -988 2001 -972 997 -1000 1005 -1968 1985 -1006 1007 -978 999 -976 1009 -1996 983 -986 1989 -2014 973 -1014 1003 -974 1009 -974 997 -986 1023 -970 1987 -1014 981 -1010 989 -984 985 -2002 1009 -960 1995 -2002 1995 -986 997 -1970 1003 -1004 1007 -978 999 -980 1013 -978 1017 -8916 2003 -1016 973 -2002 1001 -976 2013 -988 975 -1020 975 -986 1005 -1000 977 -1014 1001 -974 1007 -1000 967 -1006 997 -2002 971 -1006 1009 -980 1993 -980 1003 -986 1005 -1992 1977 -1002 975 -1014 1001 -974 1009 -1994 975 -988 1993 -2010 973 -1014 997 -980 987 -1008 983 -1018 995 -978 1975 -1006 1009 -978 999 -1008 991 -1966 1005 -998 1993 -1980 2005 -988 995 -1968 1005 -1000 1009 -978 1001 -976 1009 -980 1015 -8920 8017 -3892 1773 -165206 65 -396 99 -332 65 -100 133 -364 329 -100 199 -102 791 -100 261 -264 131 -164 295 -130 261 -100 197 -130 625 -98 299 -166 199 -100 531 -66 823 -100 327 -98 395 -98 825 -200 889 -100 295 -328 131 -98 295 -166 329 -64 393 -100 523 -66 263 -130 427 -98 463 -100 363 -166 67 -66 231 -134 331 -98 629 -132 265 -130 99 -66 953 -98 919 -296 591 -132 129 -132 591 -330 361 -166 763 -98 167 -68 265 -132 265 -130 133 -100 333 -132 295 -132 459 -132 393 -66 555 -132 263 -164 97 -64 229 -100 131 -100 329 -66 425 -64 1717 -132 7375 -66 5079 -230 199 -132 467 -66 925 -100 197 -100 231 -66 829 -166 231 -166 333 -200 359 -100 393 -164 291 -134 461 -132 325 -166 99 -100 329 -100 195 -166 399 -232 165 -98 729 -66 531 -132 99 -98 661 -332 65 -100 761 -66 427 -162 629 -132 559 -66 327 -166 597 -100 163 -66 263 -100 553 -100 789 -230 591 -198 65 -362 263 -66 327 -98 425 -66 261 -166 753 -196 889 -134 429 -134 333 -134 429 -66 231 -100 131 -100 463 -130 131 -66 753 -164 361 -64 131 -260 263 -66 359 -98 295 -100 295 -166 1163 -66 267 -68 329 -134 99 -198 233 -134 231 -132 557 -196 65 -100 263 -98 391 -98 329 -98 129 -66 diff --git a/assets/unit_tests/subghz/phoenix_v2.sub b/assets/unit_tests/subghz/phoenix_v2.sub new file mode 100644 index 000000000..3adf8aa20 --- /dev/null +++ b/assets/unit_tests/subghz/phoenix_v2.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Phoenix_V2 +Bit: 52 +Key: 00 0F 0F BD 7E 7F 10 AE diff --git a/assets/unit_tests/subghz/phoenix_v2_raw.sub b/assets/unit_tests/subghz/phoenix_v2_raw.sub new file mode 100644 index 000000000..11e155bb3 --- /dev/null +++ b/assets/unit_tests/subghz/phoenix_v2_raw.sub @@ -0,0 +1,9 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: -465 9659 -100 885 -162 2507 -98 1805 -64 427 -98 1879 -198 489 -66 525 -98 851 -100 525 -66 819 -66 395 -98 459 -66 1155 -66 863 -68 265 -98 2359 -68 435 -166 2031 -66 829 -100 561 -66 701 -66 1365 -134 731 -132 655 -68 1623 -66 263 -98 1087 -98 591 -64 987 -132 299 -66 885 -66 1087 -66 2605 -100 303 -100 731 -132 1323 -66 267 -100 627 -66 431 -100 397 -100 1027 -66 559 -102 1565 -100 865 -66 629 -100 327 -66 1281 -98 851 -132 593 -132 429 -100 2931 -134 759 -298 2985 -132 1129 -66 1131 -166 235 -100 725 -66 199 -134 365 -64 293 -66 489 -130 15135 -132 899 -100 691 -100 1271 -134 1161 -66 1789 -100 293 -64 651 -130 719 -100 1061 -66 529 -66 501 -132 1523 -68 231 -68 895 -100 1557 -134 895 -66 2297 -68 4497 -134 1319 -64 525 -98 949 -66 463 -132 399 -134 1129 -66 263 -170 1027 -100 763 -98 265 -68 603 -66 563 -166 1221 -68 1253 -66 1163 -66 697 -134 699 -98 1929 -68 931 -100 399 -100 1589 -98 663 -98 261 -66 337 -100 497 -98 767 -66 471 -66 365 -66 1363 -68 967 -300 461 -66 879 -98 623 -98 623 -100 725 -98 1685 -66 1061 -264 1523 -66 665 -130 2239 -66 229 -130 1509 -66 763 -100 1301 -132 12207 -98 261 -98 3707 -66 323 -298 821 -66 623 -98 2467 -66 2177 -164 625 -100 629 -132 1263 -132 1027 -100 2093 -132 397 -98 1855 -66 2515 -64 391 -132 1163 -66 503 -68 499 -98 2383 -98 1143 -66 523 -66 821 -98 525 -98 163 -164 1775 -68 231 -134 2159 -100 3065 -66 401 -134 925 -200 165 -18904 99 -296 261 -1018 99 -198 235 -166 329 -298 133 -266 1877 -132 227 -198 797 -66 933 -100 1093 -98 197 -66 723 -98 293 -132 953 -66 1507 -132 261 -64 1183 -98 393 -66 461 -100 863 -66 463 -100 865 -66 2721 -200 11457 -66 4203 -100 969 -66 765 -234 229 -100 491 -66 433 -66 231 -134 1189 -100 1015 -96 1349 -66 687 -132 655 -100 365 -132 397 -132 761 -100 1393 -66 525 -100 397 -132 327 -68 495 -66 429 -68 533 -134 529 -66 565 -102 695 -102 1353 -66 793 -228 197 -100 801 -64 657 -98 1439 -98 393 -98 359 -130 2707 -100 1101 -166 1523 -100 961 -100 397 -66 1217 -66 531 -166 199 -102 365 -166 1863 -66 367 -66 361 -68 703 -100 763 -100 299 -66 501 -200 231 -100 2879 -98 2005 -66 825 -134 263 -66 1155 -132 929 -66 335 -100 13393 -100 4113 -266 99 -198 1357 -66 1015 -100 1627 -66 999 -132 1329 -132 529 -66 2591 -100 2545 -68 429 -100 499 -166 961 -66 467 -66 699 +RAW_Data: -100 44175 -12032 99 -400 99 -334 65 -490 165 -328 65 -298 367 -1488 131 -166 131 -264 65 -66 99 -558 197 -198 129 -164 263 -100 2897 -66 33999 -98 1313 -166 657 -132 261 -66 197 -98 1477 -98 229 -66 1319 -66 231 -68 1199 -66 763 -100 857 -134 1963 -18216 99 -500 165 -330 65 -360 163 -202 65 -100 99 -366 267 -402 163 -68 233 -164 65 -66 167 -396 365 -100 1527 -66 393 -132 757 -66 1759 -100 821 -98 233 -66 1197 -66 399 -130 495 -100 435 -100 365 -66 199 -66 6399 -66 3541 -132 369 -132 1361 -98 597 -132 729 -68 733 -66 693 -100 199 -68 565 -134 363 -66 917 -68 267 -134 757 -132 1415 -132 327 -98 1053 -68 897 -166 263 -296 793 -102 297 -98 391 -100 893 -100 233 -68 563 -100 729 -66 431 -66 403 -68 397 -66 601 -164 563 -66 861 -132 1793 -66 637 -134 297 -66 525 -66 1421 -66 265 -100 463 -66 835 -100 699 -100 1029 -132 265 -166 567 -164 2155 -66 263 -66 1945 -100 10073 -132 463 -100 799 -66 729 -100 1655 -66 233 -66 265 -134 1961 -132 733 -98 301 -134 367 -134 1033 -64 889 -166 1463 -100 1327 -100 573 -132 497 -100 903 -100 1951 -66 427 -132 895 -198 1387 -98 723 -66 363 -100 263 -134 263 -166 561 -300 363 -198 929 -132 999 -168 65 -134 867 -132 719 -64 6625 -100 3415 -66 1553 -132 757 -130 329 -66 1625 -66 199 -66 265 -100 365 -132 267 -66 235 -100 703 -100 431 -100 601 -68 565 -100 399 -100 365 -100 365 -98 633 -100 2067 -100 495 -98 1121 -66 1253 -100 433 -132 199 -132 567 -100 99 -98 829 -198 363 -98 1717 -66 301 -132 403 -66 1791 -66 401 -100 633 -98 697 -66 1127 -66 433 -66 965 -100 2485 -66 461 -66 899 -98 231 -100 763 -100 523 -198 361 -132 1911 -66 2307 -168 265 -100 659 -134 461 -66 1165 -68 1423 -66 2693 -66 499 -66 733 -134 893 -98 435 -134 2359 -132 197 -68 661 -100 231 -68 369 -100 231 -66 495 -132 1751 -68 233 -68 1765 -132 233 -130 491 -162 855 -98 2113 -100 333 -134 765 -132 529 -66 293 -66 987 -132 329 -64 293 -98 99 -98 361 -100 367 -166 267 -68 261 -100 997 -408 855 -456 845 -868 417 -882 397 -900 411 -416 869 -884 417 -844 441 -846 427 -456 843 -452 831 -876 409 -898 409 -430 837 -462 839 -462 847 -854 417 -876 437 -880 397 -886 385 -486 841 -874 411 -868 415 -892 383 -878 439 -418 847 -466 835 -882 427 -440 843 -870 417 -882 411 -878 435 -846 427 -886 385 -886 415 -880 427 -870 409 -454 837 -888 419 +RAW_Data: -448 837 -448 835 -880 413 -448 869 -414 885 -420 849 -450 843 -876 443 -440 841 -438 873 -862 413 -448 855 -876 413 -25804 2597 -422 879 -418 867 -884 419 -844 445 -876 399 -454 849 -886 417 -878 415 -872 419 -418 893 -410 865 -876 415 -876 437 -418 851 -450 875 -418 877 -874 405 -866 419 -884 413 -878 437 -418 883 -850 415 -882 425 -874 409 -884 419 -452 851 -418 885 -850 415 -452 859 -876 409 -898 407 -862 449 -844 449 -874 409 -872 435 -870 397 -882 425 -426 875 -868 413 -452 871 -418 881 -874 413 -448 839 -460 847 -424 879 -420 867 -890 417 -416 887 -418 885 -860 413 -450 869 -848 437 -25854 475 -3978 135 -398 65 -1128 225 -1058 225 -1032 299 -562 749 -994 307 -956 341 -946 369 -488 809 -494 803 -930 353 -932 383 -474 815 -510 815 -468 811 -928 377 -914 381 -914 407 -882 399 -454 839 -890 413 -900 409 -870 417 -880 425 -442 843 -476 841 -864 417 -454 867 -882 417 -876 411 -876 435 -846 429 -882 421 -886 419 -850 445 -872 411 -450 853 -878 419 -430 881 -418 867 -890 417 -416 889 -418 885 -432 871 -416 855 -878 451 -438 845 -458 843 -884 419 -446 837 -880 449 -25864 497 -9138 659 -1080 233 -1046 297 -976 295 -558 737 -578 763 -942 339 -972 341 -530 785 -492 807 -486 807 -916 397 -918 357 -922 387 -928 383 -482 801 -906 395 -898 407 -888 415 -882 411 -480 841 -448 839 -878 415 -448 871 -876 411 -880 437 -880 397 -884 423 -884 419 -882 413 -886 387 -912 397 -466 843 -866 413 -448 869 -456 837 -888 419 -450 837 -450 851 -450 871 -454 837 -888 419 -450 835 -450 871 -884 417 -448 837 -880 415 -172818 65 -1022 197 -1852 10287 -134 695 -132 263 -130 1717 -66 625 -100 1031 -68 301 -68 265 -100 665 -98 1059 -100 931 -66 1093 -132 333 -68 3011 -132 459 -66 659 -98 521 -98 1511 -98 163 -98 857 -132 231 -98 491 -66 587 -66 393 -98 1513 -98 263 -130 529 -100 299 -100 1545 -132 1313 -66 399 -68 299 -134 201 -68 265 -98 691 -132 1099 -66 427 -100 461 -264 427 -134 327 -100 227 -64 493 -66 633 -66 501 -66 2067 -228 595 -132 97 -66 231 -66 299 -66 925 -98 661 -100 433 -134 231 -166 999 -98 691 -66 197 -66 293 -66 265 -362 1557 -100 231 -134 265 -68 433 -66 2483 -66 333 -100 233 -166 917 -132 295 -132 949 -164 1775 -100 7629 -66 7259 -66 263 -202 1263 -100 265 -68 861 -166 365 -98 233 -164 569 -66 199 -100 399 -98 1189 -130 261 -100 655 -164 723 -264 231 -100 327 -130 395 +RAW_Data: -130 84629 -16530 199 -594 163 -562 65 -164 65 -230 1383 -100 1031 -66 427 -66 401 -68 265 -102 233 -134 923 -100 493 -66 555 -132 619 -66 3165 -66 463 -198 1025 -68 233 -100 957 -132 793 -134 1233 -100 1553 -98 431 -100 1429 -100 393 -164 259 -166 65 -100 297 -134 263 -68 1797 -66 887 -100 497 -100 565 -134 363 -96 1649 -130 393 -98 327 -100 563 -68 891 -68 24545 -68 231 -134 167 -100 131 -68 863 -102 627 -164 267 -166 631 -66 569 -100 797 -66 231 -166 301 -102 569 -134 1423 -66 1115 -66 759 -66 599 -68 1265 -268 527 -134 531 -98 269 -68 231 -66 325 -98 329 -66 399 -64 393 -98 459 -98 921 -66 457 -100 2541 -266 927 -68 231 -64 357 -98 495 -166 133 -100 529 -98 1091 -100 199 -66 597 -100 931 -66 663 -134 333 -166 763 -68 599 -100 333 -102 333 -232 363 -66 1491 -132 697 -134 629 -66 369 -66 561 -134 863 -98 895 -100 199 -98 763 -100 299 -168 561 -100 331 -100 467 -100 1231 -100 1821 -66 229 -66 325 -66 1419 -66 195 -66 553 -132 363 -164 857 -66 491 -66 227 -98 227 -98 529 -100 2093 -164 501 -132 1441 -98 1095 -100 263 -66 931 -66 1397 -66 1627 -98 433 -66 697 -200 363 -266 297 -100 301 -200 263 -98 565 -134 65 -102 297 -100 165 -100 929 -266 1325 -66 3213 -100 4403 -100 665 -134 1859 -66 631 -66 967 -200 165 -134 1551 -66 791 -100 331 -132 163 -64 163 -98 361 -132 557 -98 629 -66 885 -100 1087 -100 959 -100 535 -66 265 -66 1931 -66 465 -66 1165 -100 565 -100 865 -100 493 -66 597 -166 1293 -100 463 -68 563 -66 565 -66 595 -100 197 -68 929 -66 665 -134 399 -66 665 -100 1255 -166 935 -98 1791 -98 265 -136 501 -100 1581 -66 265 -66 567 -98 699 -134 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index df36e1252..4759ed4db 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -102,4 +102,24 @@ RAW_Data: -450 1019 -482 1035 -480 1033 -460 1047 -476 1017 -484 1007 -484 1051 RAW_Data: -66 597 -100 231 -68 167 -66 1659 -100 733 -66 1631 -100 165 -66 199 -66 233 -166 165 -100 1925 -68 595 -198 1785 -134 2177 -134 131 -66 1049 -98 3087 -132 195 -64 589 -66 397 -134 329 -66 2565 -164 327 -100 689 -64 1775 -100 5183 -132 1187 -66 329 -66 395 -132 165 -98 261 -98 1247 -64 1217 -66 927 -66 997 -66 199 -98 1419 -66 531 -166 1231 -66 697 -100 97 -66 563 -66 161 -264 3205 -200 525 -98 293 -100 291 -100 133 -66 759 -66 659 -100 983 -64 523 -130 431 -166 919 -66 1097 -100 1757 -66 1119 -66 917 -98 2647 -166 1247 -66 165 -264 1189 -100 899 -134 597 -68 2323 -66 1893 -66 1095 -100 533 -64 965 -100 1817 -130 1215 -66 1879 -64 821 -164 1117 -132 263 -132 131 -66 557 -66 431 -132 661 -100 1183 -98 629 -100 1679 -132 259 -66 623 -98 431 -66 399 -164 923 -100 297 -66 165 -166 2521 -198 99 -66 431 -132 1225 -66 1063 -68 131 -136 631 -66 163 -100 99 -298 965 -68 465 -68 465 -298 2545 -134 2639 -230 1489 -66 299 -66 1991 -234 65 -132 693 -134 429 -102 101 -68 461 -66 3333 -64 1229 -68 333 -66 265 -66 885 -64 3163 -100 467 -66 2651 -164 1221 -100 1527 -66 1259 -134 431 -232 1259 -100 6029 -164 297 -98 1151 -66 1415 -100 5289 -66 2467 -100 493 -132 495 -200 1121 -66 129 -66 757 -166 327 -130 5477 -66 1227 -230 395 -100 265 -132 497 -132 1133 -132 361 -100 1051 -164 3089 -132 1583 -100 65 -68 2315 -100 529 -132 2157 -68 1257 -66 1975 -98 427 -98 1347 -66 719 -164 857 -66 165 -66 1029 -132 297 -132 467 -100 731 -130 1985 -98 199 -166 899 -100 1391 -166 3425 -100 261 -132 721 -66 4845 -98 1193 -68 1225 -66 721 -100 1015 -64 983 -66 557 -130 693 -98 99 -64 1091 -98 197 -100 2321 -66 431 -134 727 -66 467 -102 891 -98 167 -134 2619 -66 393 -64 97 -100 589 -98 1583 -164 301 -68 1481 -98 295 -98 959 -66 365 -98 1253 -66 231 -100 1255 -132 1813 -132 1645 -100 361 -132 395 -100 427 -164 1197 -98 1001 -100 861 -66 1161 -98 195 -100 197 -66 1429 -66 663 -66 1427 -98 665 -66 699 -100 663 -66 855 -196 161 -100 361 -98 823 -66 227 -66 621 -132 1853 -230 461 -230 623 -100 557 -98 229 -98 133 -134 1291 -66 533 -166 627 -134 195 -134 593 -64 591 -66 1019 -66 1049 -262 297 -100 2921 -66 133 -66 963 -134 165 -100 RAW_Data: -68 521674 -200 213 -258 217 -218 217 -246 193 -242 211 -466 451 -450 225 -212 211 -242 211 -238 243 -200 223 -254 419 -226 221 -432 251 -212 467 -240 203 -450 449 -246 205 -238 217 -218 217 -444 439 -478 431 -230 211 -462 247 -214 435 -454 449 -456 441 -442 471 -448 449 -246 205 -238 215 -220 217 -244 201 -254 217 -430 235 -220 461 -198 223 -442 275 -212 429 -458 245 -212 203 -228 253 -218 431 -448 451 -442 235 -218 463 -426 485 -214 209 -234 221 -254 219 -214 207 -228 253 -428 459 -418 245 -216 243 -194 241 -212 241 -212 211 -244 441 -228 215 -460 217 -244 435 -236 235 -440 439 -246 213 -208 229 -256 217 -430 445 -450 445 -236 253 -420 225 -232 429 -450 465 -448 439 -448 449 -454 453 -230 225 -214 241 -212 211 -242 211 -244 237 -442 237 -218 429 -230 221 -442 241 -246 425 -458 245 -212 203 -228 255 -218 427 -448 451 -446 235 -256 425 -462 417 -244 251 -208 201 -256 217 -218 209 -232 255 -420 451 -448 217 -242 211 -238 209 -234 221 -256 217 -218 437 -238 217 -464 203 -256 419 -226 223 -464 441 -244 213 -240 197 -254 219 -430 445 -452 479 -204 253 -420 225 -222 463 -452 449 -450 449 -452 447 -450 451 -238 215 -220 217 -244 199 -256 217 -218 207 -440 241 -254 423 -238 217 -462 197 -224 471 -448 225 -220 213 -242 211 -212 465 -446 449 -456 245 -214 437 -456 449 -232 233 -216 219 -254 207 -204 253 -218 219 -440 451 -456 237 -216 217 -254 209 -202 253 -218 219 -210 437 -244 253 -422 237 -218 423 -226 247 -430 451 -242 203 -228 253 -220 217 -442 449 -454 449 -240 217 -430 237 -218 461 -426 453 -450 465 -448 451 -440 443 -246 215 -250 201 -224 255 -218 215 -208 227 -442 239 -208 457 -238 219 -464 201 -256 425 -464 201 -256 217 -210 241 -216 451 -426 445 -486 207 -236 441 -430 479 -194 223 -256 217 -218 209 -234 253 -218 217 -438 449 -454 239 -216 217 -256 207 -202 255 -218 217 -210 439 -244 253 -424 235 -218 457 -224 229 -436 449 -230 221 -214 211 -242 211 -468 447 -450 449 -250 207 -454 239 -218 431 -446 451 -448 443 -486 447 -448 431 -240 207 -232 223 -254 219 -216 209 -230 253 -426 233 -234 433 -244 213 -432 237 -218 463 -446 221 -212 211 -242 239 -208 457 -456 451 -456 223 -212 467 -450 453 -204 253 -218 211 -240 215 -218 255 -208 201 -442 479 -452 203 -254 217 -212 241 -216 217 -256 207 -202 439 -240 245 -430 237 -218 463 -240 217 -428 465 -202 253 -218 213 -234 219 RAW_Data: -444 443 -452 455 -244 213 -440 237 -254 427 -450 429 -480 417 -454 477 -430 445 -244 217 -250 203 -224 253 -220 215 -206 221 -462 217 -212 467 -234 231 -440 239 -220 427 -446 219 -242 211 -244 237 -206 451 -458 451 -458 203 -254 427 -450 441 -246 213 -242 193 -244 211 -242 211 -212 241 -442 451 -454 245 -214 241 -198 255 -218 217 -210 225 -212 461 -246 213 -440 225 -242 435 -240 209 -456 457 -246 211 -204 229 -254 219 -428 445 -452 445 -238 253 -426 231 -232 435 -448 455 -448 439 -446 449 -456 451 -230 223 -214 241 -212 211 -242 211 -244 237 -442 237 -218 427 -232 221 -442 239 -246 427 -458 245 -212 205 -228 253 -220 427 -446 471 -442 237 -216 451 -462 411 -244 251 -216 205 -222 211 -242 211 -242 211 -480 453 -418 245 -252 207 -202 253 -218 219 -210 229 -256 425 -232 221 -430 251 -212 469 -204 235 -446 441 -246 213 -242 193 -244 211 -464 451 -456 441 -248 215 -450 201 -256 427 -452 457 -450 455 -450 439 -446 451 -238 217 -256 207 -202 255 -218 217 -210 231 -442 237 -244 423 -240 217 -464 203 -254 419 -454 227 -210 243 -212 241 -212 477 -418 453 -484 199 -226 431 -267004 97 -422 97 -164 65 -490 97 -2222 559 -66 163 -64 295 -100 497 -100 263 -98 361 -460 793 -66 1803 -100 339 -68 1733 +RAW_Data: 12477 16271 -64 12623 -102 40819 -98 3729 -66 14371 -66 14943 -64 5931 -66 11147 -68 74641 -102 54299 -70 18441 -66 82993 -100 66161 -68 61869 -66 6627 -66 12987 -68 30427 -68 25761 -98 6305 -66 5019 -64 30857 -132 23929 -68 25129 -39378 317 -2020 311 -2010 2033 -312 2017 -282 325 -2018 291 -2024 2035 -316 2023 -276 319 -2028 297 -2032 2029 -284 2023 -314 321 -2016 319 -2012 2003 -310 2015 -318 321 -1984 327 -16000 351 -1974 321 -2020 2041 -276 2047 -288 327 -1992 327 -2000 2055 -282 2053 -274 305 -2022 301 -2014 2049 -286 2055 -274 319 -1992 329 -2006 2065 -282 2023 -316 323 -1988 303 -16008 323 -2014 315 -1990 2053 -284 2061 -274 319 -1988 319 -2038 2033 -286 2055 -264 339 -2008 289 -2034 2035 -284 2061 -262 339 -2008 287 -2040 2037 -286 2035 -268 347 -2006 317 -15988 311 -2014 343 -2014 2027 -300 2031 -258 311 -2024 323 -2028 2023 -280 2051 -318 285 -2024 309 -2002 2039 -312 2017 -318 289 -2020 293 -2028 2035 -316 2023 -276 321 -2030 299 -15982 345 -1988 345 -2014 2029 -268 2069 -258 337 -1998 321 -2024 2025 -320 2025 -276 321 -1994 331 -2000 2057 -282 2043 -282 305 -2034 291 -2024 2039 -320 2019 -278 323 -1992 333 -15976 389 -1978 321 -1986 2069 -276 2053 -288 303 -2020 315 -1980 2067 -258 2075 -258 337 -1996 321 -2030 2027 -284 2059 -274 319 -2004 319 -2016 2033 -282 2059 -264 345 -2006 289 -16006 355 -1984 315 -2018 2033 -312 2015 -284 327 -2000 329 -2000 2063 -282 2049 -284 327 -1984 319 -2018 2035 -284 2057 -264 343 -2004 289 -2032 2059 -280 2019 -316 323 -1984 321 -15968 387 -1978 321 -1984 2069 -276 2049 -288 325 -1996 303 -2004 2055 -284 2049 -278 325 -2018 321 -1984 2075 -276 2049 -288 327 -1990 325 -1996 2031 -318 2025 -278 323 -2018 289 -16010 357 -1982 315 -2018 2035 -278 2053 -288 307 -2022 321 -2000 2049 -274 2045 -284 327 -2022 311 -2014 2033 -276 2053 -286 327 -2000 323 -2000 2061 -282 2015 -316 325 -2002 289 -15994 353 -1980 357 -1990 2035 -312 2015 -286 327 -2020 289 -2022 2033 -318 2019 -278 323 -2004 319 -2016 2059 -282 2023 -316 327 -1970 321 -2018 2059 -280 2019 -318 325 -1972 321 -15988 353 -1982 357 -1972 2071 -276 2051 -288 327 -1988 323 -1996 2061 -280 2053 -284 325 -1984 321 -2014 2031 -282 2059 -276 321 -2018 289 -2036 2031 -282 2059 -276 321 -2018 319 -15984 341 -1984 343 -2016 2029 -298 2033 -258 309 -2028 321 -2032 2035 -284 2017 -298 337 -2008 289 -2034 2027 -314 2023 -310 285 -2016 321 -2014 2035 -282 2027 -308 317 -2026 297 -15982 357 -1984 345 -1982 2067 -264 2057 -258 341 -1996 317 -2026 2057 -282 2017 -318 325 -1972 319 -2018 2059 -280 2029 -302 315 -2006 319 -2006 2059 -274 2047 -276 307 +RAW_Data: -2024 311 -15984 349 -2004 317 -2012 2029 -276 2047 -312 305 -2018 311 -2018 2037 -258 2077 -258 337 -1998 321 -2026 2031 -278 2043 -284 327 -2020 311 -2018 2031 -278 2051 -288 325 -2004 323 -15962 353 -2018 317 -2014 2007 -308 2019 -320 287 -2024 325 -1998 2035 -314 2025 -302 311 -2004 319 -2010 2027 -312 2011 -310 309 -2028 303 -2018 2027 -304 2007 -294 309 -2024 323 -16002 361 -1946 347 -2008 2027 -286 2045 -312 325 -1978 319 -2024 2043 -276 2049 -286 325 -1988 341 -1978 2061 -278 2049 -284 327 -1990 321 -2020 2029 -318 2021 -278 323 -2008 321 -15990 355 -1982 355 -1984 2031 -284 2049 -278 325 -2018 321 -2000 2047 -276 2049 -286 327 -1994 341 -1976 2067 -274 2043 -284 303 -2018 341 -1982 2061 -266 2069 -258 339 -1998 321 -16002 311 -2014 329 -2012 2027 -318 1999 -298 339 -2008 287 -2042 2031 -282 2027 -306 317 -2012 291 -2044 2037 -284 2033 -302 315 -2004 321 -2012 2037 -282 2027 -306 317 -2028 297 -15980 345 -2018 285 -2026 2037 -320 2017 -278 323 -2024 299 -2002 2069 -278 2055 -286 325 -2002 289 -2024 2037 -282 2063 -276 321 -2016 287 -2036 2025 -320 2023 -278 323 -2018 287 -16006 355 -1982 355 -1986 2033 -302 2039 -282 307 -2032 309 -2014 2043 -264 2057 -258 341 -1992 319 -2036 2033 -284 2029 -306 319 -2000 319 -2014 2035 -282 2061 -266 343 -2006 289 -16018 331 -2010 313 -2014 2021 -320 2017 -278 323 -2010 321 -2016 2037 -284 2033 -304 317 -2018 287 -2036 2037 -284 2025 -296 339 -1978 321 -2028 2057 -282 2021 -278 359 -1972 321 -15990 355 -1978 355 -1990 2035 -300 2015 -312 305 -2016 315 -2016 2053 -290 2013 -316 277 -2020 353 -1980 2059 -256 2077 -276 307 -2020 311 -2012 2047 -258 2073 -256 341 -1998 321 -15976 369 -1976 313 -2018 2051 -280 2043 -290 317 -2004 321 -2024 2023 -282 2053 -282 327 -2020 313 -2020 2035 -278 2055 -284 325 -1986 321 -2016 2033 -280 2049 -282 325 -2020 313 -15986 315 -2026 319 -2028 2003 -318 2013 -294 339 -2008 289 -2032 2027 -316 2019 -302 311 -2004 321 -2014 2033 -314 1995 -308 317 -2028 297 -2032 2035 -276 2023 -316 321 -2014 289 -15998 347 -2014 283 -2020 2035 -292 2031 -288 311 -2024 321 -2036 2001 -310 2027 -318 275 -2054 277 -2026 2029 -296 2027 -292 311 -2024 321 -2030 2031 -282 2033 -304 313 -2004 321 -15992 329 -2010 349 -1980 2037 -292 2051 -256 339 -1998 319 -2034 2029 -286 2055 -264 339 -1978 321 -2030 2027 -280 2043 -316 327 -1984 315 -2016 2063 -278 2041 -288 327 -1990 325 -15964 389 -1978 319 -1984 2063 -256 2055 -292 307 -2016 323 -2028 2027 -286 2057 -274 319 -2010 319 -2010 2033 -282 2061 -276 321 -2018 289 -2032 2027 -318 2021 -278 321 -2020 319 -15974 355 -1980 357 -2000 2035 +RAW_Data: -254 2079 -276 309 -2016 309 -2012 2035 -296 2063 -258 337 -1992 321 -2030 2037 -286 2027 -294 333 -1978 321 -2034 2029 -286 2031 -306 315 -2008 321 -15972 355 -1984 315 -2014 2037 -310 2011 -318 323 -1984 329 -2002 2033 -316 2029 -278 323 -2026 299 -2030 2035 -278 2019 -316 325 -1980 323 -2018 2053 -252 2075 -280 327 -1984 355 -15954 345 -2008 309 -2016 2045 -266 2065 -258 341 -235740 101 -202 65 -734 133 -372 401 -68 269 -236 505 -68 235 -234 875 -68 13969 -100 14297 -70 3863 -96 59337 -104 11859 -68 17409 -68 7317 -66 11443 -64 15589 -66 4381 -98 32297 -168 45445 -100 59295 -100 41417 -66 1539 -66 23001 +RAW_Data: 1549 -1166 409 -1138 363 -1144 407 -1144 385 -408 1599 -1138 377 -430 1593 -1138 421 -1110 393 -1126 409 -1136 377 -1162 353 -24626 823 -1176 379 -1150 353 -1174 349 -1158 377 -454 1541 -450 1561 -1190 383 -1118 411 -398 1557 -460 1571 -450 1547 -482 1537 -450 1561 -482 1547 -470 1537 -450 1547 -482 1539 -1176 387 -422 1541 -474 1537 -448 1545 -444 1539 -450 1543 -1136 375 -414 1549 -1142 417 -1102 387 -1118 385 -1140 381 -406 1549 -1180 383 -392 1549 -1140 417 -1122 383 -1116 383 -1140 415 -1102 355 -24628 823 -1188 357 -1180 343 -1172 385 -1150 361 -440 1513 -450 1563 -1184 369 -1158 381 -448 1539 -448 1527 -482 1545 -456 1545 -450 1533 -454 1579 -450 1561 -458 1513 -450 1555 -1182 389 -390 1571 -436 1571 -418 1581 -446 1505 -456 1511 -1160 391 -390 1339 -1108 381 -1098 361 -1150 309 -1124 331 -416 1065 -1142 353 -420 1049 -1148 319 -1156 345 -1128 347 -1134 317 -1138 319 -24716 687 -1178 309 -1138 317 -1166 319 -1162 327 -408 1039 -448 1067 -1152 321 -1132 313 -436 1065 -426 1039 -442 1039 -448 1049 -418 1041 -450 1035 -426 1039 -444 1041 -418 1047 -1144 339 -402 1069 -414 1071 -422 1051 -450 1029 -424 1069 -1144 335 -418 1043 -1178 319 -1134 321 -1174 309 -1164 313 -454 1049 -1148 317 -410 1051 -1160 353 -1124 321 -1166 349 -1122 329 -1178 277 -24734 677 -1178 299 -1182 309 -1154 337 -1144 307 -430 1047 -448 1039 -1174 319 -1164 289 -452 1033 -444 1031 -450 1035 -426 1063 -412 1047 -448 1041 -446 1033 -426 1041 -438 1049 -1152 289 -438 1071 -414 1031 -448 1039 -460 1033 -414 1079 -1146 309 -428 1049 -1178 311 -1154 337 -1144 329 -1162 319 -408 1051 -1160 353 -404 1059 -1164 317 -1154 325 -1140 347 -1152 333 -1138 285 -24770 657 -1178 315 -1162 289 -1184 313 -1152 329 -446 1039 -416 1047 -1170 343 -1128 351 -418 1021 -454 1047 -416 1061 -422 1033 -454 1043 -446 1039 -416 1065 -414 1041 -424 1033 -1178 301 -450 1041 -416 1051 -452 1045 -422 1033 -454 1043 -1172 283 -436 1065 -1146 329 -1176 311 -1150 337 -1148 309 -430 1049 -1174 299 -432 1061 -1180 289 -1178 311 -1162 347 -1150 307 -1160 311 -24722 607 -1296 203 -1264 207 -1266 227 -1252 239 -498 969 -506 1013 -1214 275 -1166 289 -480 1005 -484 1003 -476 1009 -454 1009 -480 1025 -458 1003 -448 1045 -448 1009 -450 1035 -1146 321 -444 1033 -444 1029 -444 1041 -442 1041 -416 1081 -1148 343 -396 1081 -1146 345 -1120 341 -1150 345 -1120 343 -420 1077 -1146 321 -420 1053 -1152 355 -1122 321 -1162 349 -1150 297 -1178 311 -24720 523 -4340 133 -1370 99 -636 67 -1406 393 -98 397 -1320 207 -1260 225 -498 975 -522 937 -540 977 -488 973 -510 987 -490 1005 -456 1003 -476 +RAW_Data: 1015 -450 1005 -1194 289 -454 1011 -478 1009 -478 1007 -450 1033 -446 1035 -1158 353 -404 1057 -1168 309 -1162 349 -1150 309 -1158 313 -452 1047 -1146 321 -420 1059 -1152 355 -1126 319 -1160 345 -1128 353 -1152 309 -78850 165 -1196 97 -3256 65 -626 165 -130 525 -66 625 -430 891 -492 163 -792 163 -66 197 -100 595 -132 229 -15220 165 -464 97 -66 197 -264 99 -998 67 -198 195 -132 65 -296 163 -198 65 -198 691 -66 985 -134 97 -66 1485 -15420 197 -200 63 -132 97 -526 231 -64 263 -754 425 -198 97 -166 97 -132 495 -100 555 -164 391 -98 261 -98 1221 -9074 97 -2604 65 -1942 195 -590 853 -132 1225 -66 987 -1058 97 -100 131 -132 593 -98 425 -66 3965 -11360 65 -730 299 -98 99 -66 133 -232 327 -132 65 -456 163 -132 97 -196 327 -364 561 -264 1851 -234 1191 -8710 65 -596 163 -134 99 -234 97 -168 131 -496 165 -202 65 -20716 231 -68 231 -134 363 -100 133 -132 133 -198 231 -168 131 -166 99 -162 131 -196 295 -66 261 -166 955 -98 695 -66 1215 -9510 65 -3698 165 -328 65 -492 131 -66 129 -692 231 -64 163 -132 163 -98 229 -132 131 -134 97 -100 563 -15732 197 -796 165 -132 99 -562 97 -168 295 -462 99 -66 131 -332 133 -100 299 -66 329 -132 301 -68 267 -12994 299 -98 197 -228 295 -922 63 -988 65 -100 129 -164 823 -98 931 -66 331 -98 955 -9454 231 -100 163 -134 99 -796 133 -628 263 -430 67 -364 399 -98 365 -66 889 -66 5041 -4044 131 -166 265 -298 231 -98 197 -232 197 -164 163 -198 197 -98 65 -132 3525 -15068 67 -698 133 -1056 199 -2322 959 -200 297 -232 1223 -13532 65 -1650 197 -198 65 -330 129 -100 295 -164 65 -66 131 -1290 99 -134 231 -262 889 -98 231 -64 489 -66 663 -66 563 -15458 97 -362 229 -98 165 -496 131 -266 65 -98 165 -832 729 -66 133 -18682 231 -298 263 -132 363 -132 195 -132 361 -232 197 -1480 131 -164 163 -12854 65 -2522 299 -166 1357 -132 99 -98 399 -166 329 -264 395 -64 195 -196 1055 -132 1417 -14994 197 -132 459 -824 131 -428 133 -832 231 -200 65 -432 231 -100 467 -66 1151 -100 1741 -8616 97 -6904 1085 -198 261 -196 261 -232 265 -132 563 -166 65 -166 197 -100 331 -134 2009 -8664 97 -164 65 -64 263 -132 357 -64 97 -166 493 -166 165 -98 195 -130 361 -854 891 -66 365 -166 1019 -15320 97 -198 331 -166 1359 -266 229 -134 65 -100 331 -98 65 -132 265 -20774 65 -2222 97 -66 229 -132 161 -162 133 -18134 229 -198 65 -132 197 -200 263 -364 97 -100 427 -526 65 -460 131 -428 +RAW_Data: 655 -98 2625 -8562 99 -432 97 -1924 67 -632 199 -498 65 -100 1819 -132 197 -228 263 -232 133 -296 229 -66 97 -20434 199 -432 65 -764 65 -232 233 -232 133 -334 463 -232 329 -98 357 -130 131 -132 1423 -4018 133 -1984 65 -2926 99 -930 97 -430 1293 -100 531 -66 493 -100 131 -100 429 -134 465 -132 3063 -9636 67 -3696 97 -132 229 -298 131 -694 627 -132 1247 -132 297 -166 133 -66 199 -166 663 -21440 133 -400 131 -130 99 -66 531 -232 229 -134 131 -202 165 -564 131 -1258 65 -100 133 -132 299 -166 1325 -66 833 -66 1521 -9032 97 -1544 295 -98 231 -164 261 -66 131 -394 361 -296 163 -298 463 -66 195 -96 721 -13330 65 -468 99 -134 65 -4696 199 -166 659 -98 361 -198 229 -132 557 -166 625 -164 229 -66 329 -100 131 -130 263 -66 1221 -8436 329 -198 99 -66 99 -66 165 -398 65 -1326 97 -794 165 -592 131 -66 265 -266 99 -430 2421 -100 465 -100 199 -66 699 -100 65 -132 1351 -66 897 -130 1653 -15200 231 -264 195 -296 99 -328 295 -296 163 -98 129 -98 295 -264 131 -398 65 -232 97 -98 887 -132 3157 -12396 199 -134 131 -66 231 -200 267 -132 265 -500 97 -732 131 -200 165 -396 763 -166 859 -66 1391 -9164 65 -3808 165 -66 131 -1692 65 -100 1017 -330 65 -132 65 -196 685 -198 65 -198 165 -98 231 -68 99 -22854 231 -168 67 -200 65 -66 263 -100 201 -302 65 -134 65 -22948 165 -396 263 -134 131 -68 165 -862 231 -1494 1261 -66 399 -302 3089 -6572 65 -396 65 -4140 7317 -5010 7415 -15982 811 -1174 381 -1122 381 -1148 351 -1164 345 -466 1509 -482 1541 -1176 387 -1144 363 -416 1519 -478 1525 -470 1533 -460 1539 -444 1535 -460 1531 -476 1527 -448 1513 -482 1509 -1178 379 -398 1549 -444 1539 -450 1547 -446 1541 -450 1545 -1142 381 -426 1529 -1172 381 -1140 387 -1114 395 -1130 379 -438 1531 -1172 381 -398 1555 -1192 351 -1146 407 -1122 381 -1146 381 -1126 349 -24662 821 -1174 379 -1122 383 -1146 415 -1102 385 -426 1567 -432 1567 -1178 381 -1120 385 -444 1511 -482 1515 -480 1539 -452 1545 -446 1545 -486 1541 -442 1555 -456 1495 -466 1531 -1148 387 -422 1509 -466 1533 -456 1539 -470 1503 -458 1539 -1164 351 -424 1509 -1190 353 -1148 369 -1130 379 -1136 317 -404 1331 -1128 319 -406 1231 -1140 337 -1114 349 -1122 329 -1140 349 -1120 293 -24712 627 -1236 237 -1226 233 -1230 271 -1228 239 -480 1017 -452 1039 -1184 293 -1172 275 -464 1041 -444 1007 -450 1033 -448 1035 -430 1047 -450 1031 -428 1047 -444 1005 -466 1015 -1158 289 -460 1047 -430 1033 -440 1039 -442 1033 -442 1037 -1168 309 -436 1051 -1140 +RAW_Data: 343 -1158 311 -1152 347 -1120 341 -420 1041 -1178 319 -422 1051 -1150 321 -1152 345 -1126 351 -1118 345 -1158 313 -24714 689 -1170 317 -1154 323 -1138 349 -1154 301 -448 1037 -416 1083 -1150 345 -1124 313 -454 1047 -418 1031 -446 1045 -448 1037 -416 1061 -412 1043 -442 1053 -426 1039 -436 1033 -1170 309 -418 1039 -454 1049 -418 1059 -424 1049 -452 1029 -1158 319 -454 1031 -1152 353 -1152 289 -1176 311 -1162 349 -418 1051 -1148 319 -454 1027 -1152 353 -1124 319 -1162 347 -1152 333 -1144 311 -24722 685 -1138 343 -1138 329 -1162 353 -1130 325 -412 1069 -414 1085 -1150 311 -1160 311 -422 1081 -416 1031 -444 1049 -414 1071 -416 1063 -430 1037 -440 1039 -412 1049 -450 1039 -1140 351 -420 1049 -418 1065 -420 1045 -448 1041 -414 1053 -1148 345 -398 1085 -1140 315 -1166 355 -1126 319 -1158 351 -398 1071 -1140 317 -432 1071 -1138 343 -1130 339 -1144 331 -1160 319 -1162 289 -24740 693 -1130 353 -1156 319 -1136 347 -1150 301 -448 1041 -416 1063 -1178 297 -1180 311 -428 1047 -448 1037 -416 1065 -428 1037 -442 1051 -428 1039 -440 1051 -428 1037 -434 1033 -1172 311 -414 1071 -420 1049 -428 1035 -440 1069 -414 1051 -1150 343 -398 1083 -1148 345 -1120 341 -1148 347 -1122 341 -416 1071 -1148 319 -420 1061 -1152 353 -1126 321 -1158 349 -1150 297 -1176 277 -24762 631 -1238 239 -1232 271 -1230 243 -1210 271 -470 1007 -476 993 -1222 281 -1202 269 -480 1011 -454 1035 -446 1039 -446 1041 -416 1047 -450 1045 -420 1033 -454 1015 -444 1051 -1154 321 -408 1071 -414 1065 -398 1065 -440 1049 -428 1037 -1172 317 -434 1069 -1138 317 -1152 327 -1170 315 -1164 319 -410 1081 -1162 319 -404 1061 -1166 317 -1154 325 -1140 347 -1152 333 -1148 311 -24742 691 -1138 341 -1138 317 -1164 353 -1124 319 -434 1069 -412 1069 -1148 325 -1140 347 -398 1075 -414 1069 -414 1051 -452 1047 -422 1051 -416 1057 -428 1049 -450 1029 -420 1033 -1166 335 -418 1041 -416 1063 -412 1079 -412 1071 -414 1065 -1148 325 -410 1069 -1142 351 -1152 309 -1160 349 -1116 329 -436 1051 -1162 319 -426 1051 -1148 327 -1172 311 -1156 337 -1150 345 -1120 305 -83468 65 -1920 133 -98 397 -1062 199 -464 165 -728 165 -168 97 -466 497 -132 1123 -66 3163 -12612 229 -198 65 -134 363 -66 67 -132 97 -896 197 -132 199 -166 165 -166 67 -134 165 -334 365 -134 2963 -15534 231 -132 231 -168 165 -262 97 -266 65 -724 65 -166 97 -198 295 -98 131 -132 563 -100 1483 -8892 99 -954 131 -234 67 -432 1087 -98 687 -132 163 -8794 165 -6460 165 -332 331 -498 99 -200 199 -266 67 -100 131 -596 165 -332 67 -98 299 -100 265 -68 633 -100 5793 -4102 99 -198 65 -566 +RAW_Data: 65 -658 99 -132 165 -332 167 -198 99 -132 133 -2530 65 -166 795 -300 197 -366 227 -262 361 -66 2073 -20762 65 -598 231 -264 97 -592 327 -132 295 -132 297 -100 363 -68 763 -20474 63 -166 757 -200 391 -100 97 -134 131 -134 591 -98 261 -262 229 -64 195 -100 195 -100 65 -132 261 -100 919 -66 333 -13642 65 -2324 131 -130 193 -462 195 -930 865 -66 2157 -100 1923 -12176 65 -168 197 -196 131 -1250 65 -132 391 -232 659 -66 393 -100 459 -230 197 -296 3479 -12728 99 -166 131 -134 131 -366 131 -98 97 -198 263 -164 231 -2074 693 -66 597 -66 433 -98 2509 -15286 65 -198 65 -198 165 -200 461 -132 757 -16060 65 -6768 199 -98 131 -262 163 -130 197 -198 165 -398 233 -334 65 -132 131 -166 331 -134 231 -564 365 -66 265 -100 465 -66 433 -100 6915 -6612 99 -264 65 -230 63 -4800 97 -66 393 -134 65 -100 165 -100 265 -66 165 -1818 99 -230 331 -66 265 -13068 131 -100 295 -298 427 -132 131 -1530 65 -100 165 -500 165 -132 995 -68 1685 -15810 263 -130 163 -462 231 -100 233 -632 165 -528 327 -196 197 -198 1253 -100 3583 -6278 97 -788 99 -3200 65 -166 133 -438 99 -132 165 -300 329 -166 1723 -134 725 -164 133 -16880 97 -960 99 -696 65 -200 231 -132 299 -66 297 -164 131 -730 197 -23052 365 -66 99 -332 131 -166 297 -494 429 -1326 265 -132 295 -66 367 -232 263 -66 857 -15396 395 -130 229 -98 233 -132 331 -364 65 -100 529 -68 231 -830 297 -100 233 -66 8533 -5582 101 -168 67 -3968 231 -66 129 -132 163 -1154 97 -166 199 -166 233 -132 467 -134 263 -66 431 -66 363 -66 957 -100 1821 -132 497 -132 1159 -15358 397 -66 99 -98 65 -66 265 -564 65 -68 97 -166 99 -100 165 -134 297 -896 165 -330 97 -134 963 -132 4737 -7096 65 -5664 265 -266 97 -166 265 -598 65 -332 65 -66 65 -198 231 -132 329 -100 65 -17202 99 -1564 595 -98 329 -198 227 -66 459 -230 97 -1480 63 -66 131 -166 99 -166 931 -8662 133 -398 99 -134 265 -98 299 -264 233 -66 99 -100 99 -66 97 -166 199 -166 265 -234 5785 -10012 163 -2324 331 -196 331 -134 65 -100 297 -100 165 -100 131 -332 163 -302 297 -164 199 -300 199 -166 229 -68 99 -68 959 -15384 365 -134 263 -1818 229 -698 99 -232 131 -100 789 -66 491 -132 4039 -12084 99 -134 331 -796 265 -132 265 -362 167 -2310 65 -98 131 -100 525 -164 295 -15032 297 -560 197 -330 131 -196 397 -266 197 -200 263 -68 261 -496 329 -166 361 -166 1517 -66 331 -10126 97 -3736 99 -1626 131 -100 +RAW_Data: 3487 -68 18413 -66 6689 -17938 65 -68 495 -98 1129 -860 697 -166 395 -100 463 -100 163 -14692 263 -794 65 -64 99 -2922 131 -200 97 -168 99 -100 199 -962 495 -68 165 -98 299 -198 133 -168 3917 -98 963 -132 461 -100 1089 -166 331 -134 633 -164 201 -100 363 -164 335 -200 265 -68 531 -166 699 -132 529 -166 397 -98 895 -168 65 -100 399 -366 463 -66 197 -134 431 -66 163 -98 623 -166 301 -98 263 -98 263 -66 197 -98 329 -98 525 -66 331 -200 1025 -66 629 -132 763 -166 233 -66 431 -132 133 -100 429 -264 165 -132 299 -166 429 -68 4605 -134 593 -134 4917 -60834 167 -10282 1941 -1122 865 -2086 921 -1072 1921 -1042 939 -1056 945 -1044 939 -1052 945 -1024 971 -1024 973 -1002 969 -1010 989 -1996 1007 -994 979 -1014 1965 -1014 977 -1020 969 -2004 1993 -982 1011 -982 1005 -984 977 -2008 981 -1006 1993 -1966 999 -994 1007 -982 1005 -984 1007 -996 975 -1016 1987 -996 973 -1016 969 -1004 1013 -1970 1011 -984 1999 -1970 1995 -984 1021 -1968 1005 -994 1003 -970 999 -984 1023 -974 1015 -8920 1995 -1014 1001 -1966 1013 -986 1991 -986 1007 -996 973 -1012 999 -978 985 -1006 1005 -984 997 -978 1015 -1000 973 -1982 1025 -982 985 -1008 1973 -1004 1007 -982 983 -1998 2009 -972 1009 -980 999 -978 1011 -1970 1011 -986 1999 -1978 1007 -988 1007 -994 975 -1012 1003 -972 1009 -978 1987 -986 1007 -982 1017 -994 971 -1990 1009 -984 1997 -1978 1999 -1010 993 -1964 1005 -1000 1007 -980 997 -984 1017 -972 999 -8932 2031 -980 989 -1988 985 -1016 1983 -986 1007 -994 975 -1016 975 -998 977 -1012 999 -982 985 -1006 983 -1018 993 -1968 1017 -996 975 -1016 1965 -1012 979 -1018 971 -2004 1991 -978 1003 -984 1015 -992 973 -2004 1005 -976 1991 -2008 975 -986 1005 -998 977 -1012 999 -978 985 -1010 1973 -1004 1013 -980 981 -1004 1007 -1996 975 -986 1993 -2006 1961 -1002 1013 -1974 985 -1008 1011 -978 997 -1006 981 -1012 991 -8918 8005 -3924 1887 -174620 131 -3974 131 -298 559 -230 65 -132 265 -98 863 -168 333 -66 299 -234 463 -166 331 -102 697 -200 199 -98 265 -100 663 -166 331 -66 599 -132 99 -66 1261 -66 399 -100 265 -100 1199 -66 265 -166 101 -66 599 -232 197 -100 561 -66 499 -132 797 -132 427 -66 265 -298 465 -66 565 -198 97 -100 695 -100 531 -132 267 -66 429 -98 231 -100 331 -100 333 -98 363 -198 67 -100 165 -100 231 -100 729 -134 1061 -100 493 -164 665 -132 259 -128 257 -130 329 -98 361 -66 263 -100 227 -66 491 -98 295 -166 229 -132 229 -130 263 -130 233 -100 331 -232 99 -100 165 -66 667 -164 795 -66 695 -68 429 -132 +RAW_Data: 559 -66 16863 -66 19215 -12276 65 -2086 131 -2188 65 -132 67 -166 299 -364 65 -100 131 -468 233 -200 497 -498 297 -100 363 -198 329 -130 327 -164 229 -64 427 -164 657 -132 829 -532 895 -66 297 -130 425 -166 363 -132 329 -100 465 -100 465 -198 65 -262 429 -98 495 -100 295 -528 131 -132 1129 -134 259 -130 327 -100 397 -66 261 -230 99 -66 229 -132 625 -68 131 -100 587 -66 329 -64 293 -130 1741 -132 325 -132 197 -98 261 -98 99 -132 561 -166 165 -66 391 -66 329 -98 231 -132 465 -100 331 -300 199 -132 299 -132 165 -164 229 -98 565 -100 395 -132 131 -100 327 -130 97 -98 163 -132 293 -98 557 -66 199 -166 233 -132 265 -166 627 -100 265 -132 595 -166 99 -98 199 -100 267 -166 795 -166 265 -166 297 -66 131 -166 331 -134 793 -164 263 -198 299 -100 265 -166 257 -100 197 -198 599 -132 333 -66 265 -100 229 -100 165 -204 465 -166 97 -232 365 -166 431 -68 199 -166 99 -236 365 -132 1297 -66 1361 -100 989 -98 297 -132 12467 -232 361 -100 263 -132 261 -196 229 -296 65 -66 329 -164 229 -164 263 -66 563 -232 3415 -132 11115 -100 97 -100 363 -164 99 -66 199 -100 99 -66 561 -164 259 -168 233 -132 333 -166 567 -98 297 -66 399 -66 399 -298 327 -132 685 -98 393 -98 819 -100 231 -270 429 -68 461 -132 131 -134 1121 -230 787 -132 1393 -132 233 -100 331 -66 497 -166 563 -196 425 -98 525 -66 723 -98 265 -134 365 -66 1297 -166 433 -98 165 -134 231 -134 263 -100 369 -198 99 -100 631 -634 331 -132 565 -132 265 -102 267 -98 467 -200 297 -130 731 -100 367 -98 229 -130 99 -98 263 -164 493 -100 297 -198 429 -66 425 -66 1021 -164 295 -198 97 -198 263 -132 425 -98 493 -98 197 -98 593 -264 65 -294 197 -66 295 -66 561 -196 565 -166 2675 -132 19393 -134 5403 -164 369 -166 467 -132 361 -526 395 -66 361 -132 529 -66 431 -66 465 -166 363 -98 65 -98 229 -98 359 -100 197 -132 201 -100 467 -166 397 -100 297 -130 229 -98 361 -98 199 -130 297 -66 659 -132 261 -98 819 -98 393 -132 329 -132 557 -132 163 -130 657 -66 295 -134 1189 -100 399 -102 861 -100 369 -132 331 -134 263 -666 65 -134 427 -64 197 -98 559 -68 297 -98 493 -164 197 -164 525 -66 131 -98 493 -66 595 -100 233 -100 265 -132 65 -66 465 -266 527 -98 855 -132 493 -66 393 -298 331 -100 131 -66 859 -198 495 -100 265 -98 367 -66 727 -196 535 -66 263 -66 397 -332 65 -198 331 -134 297 -330 +RAW_Data: 261 -100 3291 -68 2553 -19050 1855 -100 1259 -200 165 -100 39479 -100 233 -68 1027 -166 595 -66 231 -168 199 -98 265 -232 563 -166 795 -98 99 -460 65 -362 1017 -98 229 -98 625 -66 231 -98 161 -196 363 -98 363 -100 631 -132 297 -66 333 -300 99 -66 295 -230 985 -100 623 -132 1319 -100 65 -68 231 -232 197 -232 331 -100 199 -168 567 -166 133 -232 823 -396 327 -132 855 -232 165 -100 401 -166 599 -198 167 -132 299 -198 663 -132 165 -134 67 -66 1687 -66 1705 -100 265 -232 297 -100 531 -66 333 -100 1263 -66 297 -164 299 -98 431 -398 97 -66 199 -296 231 -232 925 -100 131 -132 229 -164 361 -66 267 -166 197 -100 491 -132 261 -132 1183 -98 891 -100 265 -100 99 -100 725 -100 303 -60886 131 -10310 1911 -1226 749 -2146 899 -1084 1905 -1070 917 -1044 973 -1042 927 -1050 949 -1044 965 -1012 949 -1046 965 -1014 977 -2008 981 -980 995 -1012 1969 -1018 971 -1014 975 -2014 1967 -1016 971 -1014 977 -984 1003 -2006 973 -1000 2001 -1978 1013 -980 1001 -972 1009 -978 991 -1010 983 -1004 1989 -1012 983 -978 995 -1014 983 -2002 977 -984 2023 -1968 1997 -986 999 -1970 1003 -1000 1009 -978 1017 -974 1009 -978 1001 -8948 1975 -1016 973 -2004 999 -978 2001 -986 1001 -978 1009 -986 1001 -1010 975 -998 1011 -992 975 -982 1005 -1000 1009 -1970 1011 -982 1009 -984 2003 -978 1001 -976 1015 -1966 1999 -1010 989 -982 989 -1004 1001 -1978 1013 -978 2005 -1966 1019 -972 1011 -980 997 -976 1011 -1004 999 -966 1997 -1000 999 -1002 975 -986 999 -1994 1007 -980 1993 -1978 2001 -1008 991 -1970 1009 -998 975 -1016 971 -1006 1013 -980 1001 -8922 2001 -994 1009 -1972 997 -1012 1971 -984 1005 -1012 977 -998 1009 -978 1011 -984 977 -1012 979 -1016 977 -1010 977 -2010 981 -1006 971 -1020 1985 -984 1005 -978 999 -1990 1997 -980 997 -1010 981 -1014 989 -1976 1005 -966 1995 -1998 997 -982 1021 -972 1003 -986 997 -1012 975 -982 1995 -1014 999 -980 983 -1004 1003 -1976 1007 -980 1983 -2012 1983 -998 977 -2010 973 -1014 973 -1018 973 -1014 975 -1016 971 -8956 7999 -3926 1865 -177334 165 -166 199 -496 431 -66 1319 -132 297 -164 457 -68 231 -100 863 -98 603 -100 663 -100 789 -262 491 -166 729 -100 795 -364 365 -132 293 -100 197 -98 625 -200 231 -132 229 -132 227 -100 755 -526 329 -134 793 -100 167 -200 335 -66 65 -134 265 -66 201 -66 1023 -100 63 -21396 133 -198 65 -66 263 -98 393 -134 65 -66 329 -68 199 -432 263 -394 131 -130 195 -66 687 -66 295 -164 229 -196 97 -98 559 -98 1283 -98 531 -66 331 -68 435 -100 393 -628 431 -132 99 -66 +RAW_Data: 329 -66 2519 -100 6759 -12690 463 -232 97 -3252 65 -2592 65 -132 99 -198 67 -496 99 -300 231 -132 233 -66 165 -132 131 -164 201 -66 4113 -66 1987 -68 15385 -98 8199 -16614 165 -1258 495 -1354 229 -166 297 -134 3653 -100 12533 -66 3759 -162 591 -132 361 -130 527 -100 327 -200 65 -66 461 -132 327 -132 461 -100 559 -198 263 -132 161 -98 329 -132 327 -68 395 -66 165 -132 163 -196 261 -66 361 -98 229 -132 301 -134 761 -66 399 -166 99 -66 461 -98 857 -98 131 -262 359 -132 199 -100 299 -166 363 -132 297 -132 199 -132 265 -166 133 -100 301 -268 463 -98 231 -134 265 -98 527 -298 265 -136 531 -132 363 -132 129 -130 527 -132 297 -66 297 -68 397 -466 99 -132 697 -98 233 -464 131 -132 365 -134 465 -98 635 -98 299 -66 497 -132 197 -132 489 -166 327 -98 1151 -130 295 -132 623 -164 97 -68 297 -100 1293 -100 1759 -66 1259 -132 729 -100 797 -66 99 -66 231 -98 529 -166 331 -166 299 -202 431 -134 467 -462 329 -462 1051 -98 625 -66 195 -100 461 -196 429 -132 197 -66 129 -66 229 -166 589 -164 629 -66 1053 -166 231 -98 263 -132 329 -132 267 -132 427 -130 65 -130 229 -166 4121 -66 15899 -19980 495 -264 165 -432 65 -132 65 -662 663 -100 793 -66 723 -164 565 -100 363 -166 199 -98 465 -100 299 -168 265 -198 695 -132 131 -268 497 -66 265 -134 199 -98 231 -134 499 -100 989 -132 429 -196 327 -132 131 -164 427 -66 263 -66 525 -132 1091 -100 793 -132 491 -66 195 -526 921 -134 363 -98 693 -230 165 -98 1711 -132 293 -66 659 -196 231 -66 261 -66 163 -66 1349 -166 363 -100 65 -100 299 -100 393 -66 495 -134 229 -98 131 -98 463 -362 361 -132 231 -66 491 -396 361 -132 97 -66 163 -198 229 -294 229 -198 165 -164 65 -100 623 -66 195 -98 261 -130 65 -98 563 -66 267 -166 1057 -632 531 -132 463 -100 663 -166 133 -100 569 -164 197 -66 431 -164 261 -132 363 -100 427 -164 263 -198 623 -66 589 -166 133 -166 199 -66 199 -268 65 -98 427 -66 163 -132 563 -198 363 -166 397 -98 1025 -66 197 -66 163 -132 693 -164 195 -66 427 -100 131 -66 433 -132 199 -402 231 -66 335 -100 993 -100 463 -232 65 -100 65 -66 7165 -66 6785 -66 895 -66 923 -198 97 -164 689 -166 361 -198 99 -66 753 -498 365 -66 567 -232 397 -66 199 -132 233 -200 995 -296 365 -166 597 -100 199 -134 99 -166 197 -332 431 -166 331 -66 199 -100 431 -232 493 -166 457 -98 231 -132 427 -230 559 -98 +RAW_Data: 261 -132 1051 -66 7501 -98 22107 -19232 2271 -166 133 -60834 165 -10284 595 -5446 885 -1106 1891 -1088 897 -1068 949 -1050 929 -1040 947 -1048 959 -1008 985 -1008 973 -1012 993 -2004 979 -998 975 -1014 1987 -998 977 -1014 971 -1998 2007 -974 1013 -976 999 -982 1023 -1962 1005 -1000 1969 -2010 977 -1016 971 -1004 1009 -980 985 -1002 979 -1014 1977 -1012 979 -1016 971 -1012 977 -1986 1021 -974 2005 -1968 2007 -976 1011 -1966 1009 -984 1009 -984 985 -1020 969 -1002 997 -8952 1995 -986 1017 -1988 989 -976 1979 -1028 975 -988 1009 -986 1007 -992 973 -1014 1001 -974 1011 -978 995 -1006 979 -2004 975 -1022 973 -984 1999 -1014 977 -984 1003 -2004 1995 -976 1005 -998 999 -982 981 -2002 983 -986 1989 -1998 1009 -976 999 -1010 991 -978 1013 -968 1011 -986 1995 -982 1023 -974 981 -1020 993 -1970 1007 -996 1995 -1982 1999 -986 993 -2002 985 -998 975 -1014 969 -1004 1009 -978 997 -8962 1989 -990 1009 -1954 1025 -984 2007 -962 1011 -980 1001 -982 1009 -1002 1007 -980 1005 -976 1007 -980 997 -976 1009 -2002 977 -988 1005 -982 2001 -976 1009 -988 1005 -1968 2029 -974 1003 -990 1011 -958 1005 -1972 1039 -978 1999 -1978 1009 -954 1037 -978 1007 -954 1039 -980 1011 -958 1999 -974 1031 -990 993 -972 1011 -1980 1011 -978 2009 -1968 1993 -982 1003 -1974 1007 -1006 1001 -986 985 -986 1001 -982 1033 -8924 8013 -3924 1851 -170400 493 -132 131 -164 65 -724 461 -164 693 -100 265 -100 229 -100 199 -98 363 -232 363 -100 131 -68 531 -166 165 -134 265 -66 727 -300 131 -198 99 -132 99 -134 597 -102 295 -130 131 -230 129 -98 689 -264 263 -134 231 -134 199 -132 131 -68 295 -100 163 -130 591 -98 327 -164 231 -66 589 -98 2077 -134 1389 -66 2913 -66 3045 -66 4463 -98 391 -132 489 -164 295 -66 523 -166 329 -98 195 -98 165 -100 165 -66 231 -100 895 -98 265 -132 595 -132 297 -494 261 -198 331 -100 131 -134 429 -68 231 -298 1193 -66 99 -100 627 -132 331 -98 393 -98 657 -132 163 -392 359 -132 163 -64 655 -164 263 -64 531 -98 265 -164 499 -100 229 -64 459 -100 199 -66 165 -130 197 -132 393 -66 163 -228 229 -132 65 -132 263 -100 357 -98 991 -328 595 -132 197 -130 759 -66 131 -166 267 -100 1251 -64 361 -66 395 -954 559 -132 295 -98 327 -100 295 -100 367 -198 391 -298 363 -132 495 -132 523 -66 97 -132 763 -198 131 -66 197 -100 525 -130 1059 -64 461 -166 563 -134 331 -66 463 -134 329 -198 199 -166 265 -266 1061 -66 331 -366 65 -66 1225 -100 299 -66 299 -132 133 -298 265 -100 1129 -364 163 -460 297 -132 297 -100 299 -100 +RAW_Data: -465 9659 -100 885 -162 2507 -98 1805 -64 427 -98 1879 -198 489 -66 525 -98 851 -100 525 -66 819 -66 395 -98 459 -66 1155 -66 863 -68 265 -98 2359 -68 435 -166 2031 -66 829 -100 561 -66 701 -66 1365 -134 731 -132 655 -68 1623 -66 263 -98 1087 -98 591 -64 987 -132 299 -66 885 -66 1087 -66 2605 -100 303 -100 731 -132 1323 -66 267 -100 627 -66 431 -100 397 -100 1027 -66 559 -102 1565 -100 865 -66 629 -100 327 -66 1281 -98 851 -132 593 -132 429 -100 2931 -134 759 -298 2985 -132 1129 -66 1131 -166 235 -100 725 -66 199 -134 365 -64 293 -66 489 -130 15135 -132 899 -100 691 -100 1271 -134 1161 -66 1789 -100 293 -64 651 -130 719 -100 1061 -66 529 -66 501 -132 1523 -68 231 -68 895 -100 1557 -134 895 -66 2297 -68 4497 -134 1319 -64 525 -98 949 -66 463 -132 399 -134 1129 -66 263 -170 1027 -100 763 -98 265 -68 603 -66 563 -166 1221 -68 1253 -66 1163 -66 697 -134 699 -98 1929 -68 931 -100 399 -100 1589 -98 663 -98 261 -66 337 -100 497 -98 767 -66 471 -66 365 -66 1363 -68 967 -300 461 -66 879 -98 623 -98 623 -100 725 -98 1685 -66 1061 -264 1523 -66 665 -130 2239 -66 229 -130 1509 -66 763 -100 1301 -132 12207 -98 261 -98 3707 -66 323 -298 821 -66 623 -98 2467 -66 2177 -164 625 -100 629 -132 1263 -132 1027 -100 2093 -132 397 -98 1855 -66 2515 -64 391 -132 1163 -66 503 -68 499 -98 2383 -98 1143 -66 523 -66 821 -98 525 -98 163 -164 1775 -68 231 -134 2159 -100 3065 -66 401 -134 925 -200 165 -18904 99 -296 261 -1018 99 -198 235 -166 329 -298 133 -266 1877 -132 227 -198 797 -66 933 -100 1093 -98 197 -66 723 -98 293 -132 953 -66 1507 -132 261 -64 1183 -98 393 -66 461 -100 863 -66 463 -100 865 -66 2721 -200 11457 -66 4203 -100 969 -66 765 -234 229 -100 491 -66 433 -66 231 -134 1189 -100 1015 -96 1349 -66 687 -132 655 -100 365 -132 397 -132 761 -100 1393 -66 525 -100 397 -132 327 -68 495 -66 429 -68 533 -134 529 -66 565 -102 695 -102 1353 -66 793 -228 197 -100 801 -64 657 -98 1439 -98 393 -98 359 -130 2707 -100 1101 -166 1523 -100 961 -100 397 -66 1217 -66 531 -166 199 -102 365 -166 1863 -66 367 -66 361 -68 703 -100 763 -100 299 -66 501 -200 231 -100 2879 -98 2005 -66 825 -134 263 -66 1155 -132 929 -66 335 -100 13393 -100 4113 -266 99 -198 1357 -66 1015 -100 1627 -66 999 -132 1329 -132 529 -66 2591 -100 2545 -68 429 -100 499 -166 961 -66 467 -66 699 +RAW_Data: -100 44175 -12032 99 -400 99 -334 65 -490 165 -328 65 -298 367 -1488 131 -166 131 -264 65 -66 99 -558 197 -198 129 -164 263 -100 2897 -66 33999 -98 1313 -166 657 -132 261 -66 197 -98 1477 -98 229 -66 1319 -66 231 -68 1199 -66 763 -100 857 -134 1963 -18216 99 -500 165 -330 65 -360 163 -202 65 -100 99 -366 267 -402 163 -68 233 -164 65 -66 167 -396 365 -100 1527 -66 393 -132 757 -66 1759 -100 821 -98 233 -66 1197 -66 399 -130 495 -100 435 -100 365 -66 199 -66 6399 -66 3541 -132 369 -132 1361 -98 597 -132 729 -68 733 -66 693 -100 199 -68 565 -134 363 -66 917 -68 267 -134 757 -132 1415 -132 327 -98 1053 -68 897 -166 263 -296 793 -102 297 -98 391 -100 893 -100 233 -68 563 -100 729 -66 431 -66 403 -68 397 -66 601 -164 563 -66 861 -132 1793 -66 637 -134 297 -66 525 -66 1421 -66 265 -100 463 -66 835 -100 699 -100 1029 -132 265 -166 567 -164 2155 -66 263 -66 1945 -100 10073 -132 463 -100 799 -66 729 -100 1655 -66 233 -66 265 -134 1961 -132 733 -98 301 -134 367 -134 1033 -64 889 -166 1463 -100 1327 -100 573 -132 497 -100 903 -100 1951 -66 427 -132 895 -198 1387 -98 723 -66 363 -100 263 -134 263 -166 561 -300 363 -198 929 -132 999 -168 65 -134 867 -132 719 -64 6625 -100 3415 -66 1553 -132 757 -130 329 -66 1625 -66 199 -66 265 -100 365 -132 267 -66 235 -100 703 -100 431 -100 601 -68 565 -100 399 -100 365 -100 365 -98 633 -100 2067 -100 495 -98 1121 -66 1253 -100 433 -132 199 -132 567 -100 99 -98 829 -198 363 -98 1717 -66 301 -132 403 -66 1791 -66 401 -100 633 -98 697 -66 1127 -66 433 -66 965 -100 2485 -66 461 -66 899 -98 231 -100 763 -100 523 -198 361 -132 1911 -66 2307 -168 265 -100 659 -134 461 -66 1165 -68 1423 -66 2693 -66 499 -66 733 -134 893 -98 435 -134 2359 -132 197 -68 661 -100 231 -68 369 -100 231 -66 495 -132 1751 -68 233 -68 1765 -132 233 -130 491 -162 855 -98 2113 -100 333 -134 765 -132 529 -66 293 -66 987 -132 329 -64 293 -98 99 -98 361 -100 367 -166 267 -68 261 -100 997 -408 855 -456 845 -868 417 -882 397 -900 411 -416 869 -884 417 -844 441 -846 427 -456 843 -452 831 -876 409 -898 409 -430 837 -462 839 -462 847 -854 417 -876 437 -880 397 -886 385 -486 841 -874 411 -868 415 -892 383 -878 439 -418 847 -466 835 -882 427 -440 843 -870 417 -882 411 -878 435 -846 427 -886 385 -886 415 -880 427 -870 409 -454 837 -888 419 +RAW_Data: -448 837 -448 835 -880 413 -448 869 -414 885 -420 849 -450 843 -876 443 -440 841 -438 873 -862 413 -448 855 -876 413 -25804 2597 -422 879 -418 867 -884 419 -844 445 -876 399 -454 849 -886 417 -878 415 -872 419 -418 893 -410 865 -876 415 -876 437 -418 851 -450 875 -418 877 -874 405 -866 419 -884 413 -878 437 -418 883 -850 415 -882 425 -874 409 -884 419 -452 851 -418 885 -850 415 -452 859 -876 409 -898 407 -862 449 -844 449 -874 409 -872 435 -870 397 -882 425 -426 875 -868 413 -452 871 -418 881 -874 413 -448 839 -460 847 -424 879 -420 867 -890 417 -416 887 -418 885 -860 413 -450 869 -848 437 -25854 475 -3978 135 -398 65 -1128 225 -1058 225 -1032 299 -562 749 -994 307 -956 341 -946 369 -488 809 -494 803 -930 353 -932 383 -474 815 -510 815 -468 811 -928 377 -914 381 -914 407 -882 399 -454 839 -890 413 -900 409 -870 417 -880 425 -442 843 -476 841 -864 417 -454 867 -882 417 -876 411 -876 435 -846 429 -882 421 -886 419 -850 445 -872 411 -450 853 -878 419 -430 881 -418 867 -890 417 -416 889 -418 885 -432 871 -416 855 -878 451 -438 845 -458 843 -884 419 -446 837 -880 449 -25864 497 -9138 659 -1080 233 -1046 297 -976 295 -558 737 -578 763 -942 339 -972 341 -530 785 -492 807 -486 807 -916 397 -918 357 -922 387 -928 383 -482 801 -906 395 -898 407 -888 415 -882 411 -480 841 -448 839 -878 415 -448 871 -876 411 -880 437 -880 397 -884 423 -884 419 -882 413 -886 387 -912 397 -466 843 -866 413 -448 869 -456 837 -888 419 -450 837 -450 851 -450 871 -454 837 -888 419 -450 835 -450 871 -884 417 -448 837 -880 415 -172818 65 -1022 197 -1852 10287 -134 695 -132 263 -130 1717 -66 625 -100 1031 -68 301 -68 265 -100 665 -98 1059 -100 931 -66 1093 -132 333 -68 3011 -132 459 -66 659 -98 521 -98 1511 -98 163 -98 857 -132 231 -98 491 -66 587 -66 393 -98 1513 -98 263 -130 529 -100 299 -100 1545 -132 1313 -66 399 -68 299 -134 201 -68 265 -98 691 -132 1099 -66 427 -100 461 -264 427 -134 327 -100 227 -64 493 -66 633 -66 501 -66 2067 -228 595 -132 97 -66 231 -66 299 -66 925 -98 661 -100 433 -134 231 -166 999 -98 691 -66 197 -66 293 -66 265 -362 1557 -100 231 -134 265 -68 433 -66 2483 -66 333 -100 233 -166 917 -132 295 -132 949 -164 1775 -100 7629 -66 7259 -66 263 -202 1263 -100 265 -68 861 -166 365 -98 233 -164 569 -66 199 -100 399 -98 1189 -130 261 -100 655 -164 723 -264 231 -100 327 -130 395 +RAW_Data: -130 84629 -16530 199 -594 163 -562 65 -164 65 -230 1383 -100 1031 -66 427 -66 401 -68 265 -102 233 -134 923 -100 493 -66 555 -132 619 -66 3165 -66 463 -198 1025 -68 233 -100 957 -132 793 -134 1233 -100 1553 -98 431 -100 1429 -100 393 -164 259 -166 65 -100 297 -134 263 -68 1797 -66 887 -100 497 -100 565 -134 363 -96 1649 -130 393 -98 327 -100 563 -68 891 -68 24545 -68 231 -134 167 -100 131 -68 863 -102 627 -164 267 -166 631 -66 569 -100 797 -66 231 -166 301 -102 569 -134 1423 -66 1115 -66 759 -66 599 -68 1265 -268 527 -134 531 -98 269 -68 231 -66 325 -98 329 -66 399 -64 393 -98 459 -98 921 -66 457 -100 2541 -266 927 -68 231 -64 357 -98 495 -166 133 -100 529 -98 1091 -100 199 -66 597 -100 931 -66 663 -134 333 -166 763 -68 599 -100 333 -102 333 -232 363 -66 1491 -132 697 -134 629 -66 369 -66 561 -134 863 -98 895 -100 199 -98 763 -100 299 -168 561 -100 331 -100 467 -100 1231 -100 1821 -66 229 -66 325 -66 1419 -66 195 -66 553 -132 363 -164 857 -66 491 -66 227 -98 227 -98 529 -100 2093 -164 501 -132 1441 -98 1095 -100 263 -66 931 -66 1397 -66 1627 -98 433 -66 697 -200 363 -266 297 -100 301 -200 263 -98 565 -134 65 -102 297 -100 165 -100 929 -266 1325 -66 3213 -100 4403 -100 665 -134 1859 -66 631 -66 967 -200 165 -134 1551 -66 791 -100 331 -132 163 -64 163 -98 361 -132 557 -98 629 -66 885 -100 1087 -100 959 -100 535 -66 265 -66 1931 -66 465 -66 1165 -100 565 -100 865 -100 493 -66 597 -166 1293 -100 463 -68 563 -66 565 -66 595 -100 197 -68 929 -66 665 -134 399 -66 665 -100 1255 -166 935 -98 1791 -98 265 -136 501 -100 1581 -66 265 -66 567 -98 699 -134 +RAW_Data: 12477 16271 -64 12623 -102 40819 -98 3729 -66 14371 -66 14943 -64 5931 -66 11147 -68 74641 -102 54299 -70 18441 -66 82993 -100 66161 -68 61869 -66 6627 -66 12987 -68 30427 -68 25761 -98 6305 -66 5019 -64 30857 -132 23929 -68 25129 -39378 317 -2020 311 -2010 2033 -312 2017 -282 325 -2018 291 -2024 2035 -316 2023 -276 319 -2028 297 -2032 2029 -284 2023 -314 321 -2016 319 -2012 2003 -310 2015 -318 321 -1984 327 -16000 351 -1974 321 -2020 2041 -276 2047 -288 327 -1992 327 -2000 2055 -282 2053 -274 305 -2022 301 -2014 2049 -286 2055 -274 319 -1992 329 -2006 2065 -282 2023 -316 323 -1988 303 -16008 323 -2014 315 -1990 2053 -284 2061 -274 319 -1988 319 -2038 2033 -286 2055 -264 339 -2008 289 -2034 2035 -284 2061 -262 339 -2008 287 -2040 2037 -286 2035 -268 347 -2006 317 -15988 311 -2014 343 -2014 2027 -300 2031 -258 311 -2024 323 -2028 2023 -280 2051 -318 285 -2024 309 -2002 2039 -312 2017 -318 289 -2020 293 -2028 2035 -316 2023 -276 321 -2030 299 -15982 345 -1988 345 -2014 2029 -268 2069 -258 337 -1998 321 -2024 2025 -320 2025 -276 321 -1994 331 -2000 2057 -282 2043 -282 305 -2034 291 -2024 2039 -320 2019 -278 323 -1992 333 -15976 389 -1978 321 -1986 2069 -276 2053 -288 303 -2020 315 -1980 2067 -258 2075 -258 337 -1996 321 -2030 2027 -284 2059 -274 319 -2004 319 -2016 2033 -282 2059 -264 345 -2006 289 -16006 355 -1984 315 -2018 2033 -312 2015 -284 327 -2000 329 -2000 2063 -282 2049 -284 327 -1984 319 -2018 2035 -284 2057 -264 343 -2004 289 -2032 2059 -280 2019 -316 323 -1984 321 -15968 387 -1978 321 -1984 2069 -276 2049 -288 325 -1996 303 -2004 2055 -284 2049 -278 325 -2018 321 -1984 2075 -276 2049 -288 327 -1990 325 -1996 2031 -318 2025 -278 323 -2018 289 -16010 357 -1982 315 -2018 2035 -278 2053 -288 307 -2022 321 -2000 2049 -274 2045 -284 327 -2022 311 -2014 2033 -276 2053 -286 327 -2000 323 -2000 2061 -282 2015 -316 325 -2002 289 -15994 353 -1980 357 -1990 2035 -312 2015 -286 327 -2020 289 -2022 2033 -318 2019 -278 323 -2004 319 -2016 2059 -282 2023 -316 327 -1970 321 -2018 2059 -280 2019 -318 325 -1972 321 -15988 353 -1982 357 -1972 2071 -276 2051 -288 327 -1988 323 -1996 2061 -280 2053 -284 325 -1984 321 -2014 2031 -282 2059 -276 321 -2018 289 -2036 2031 -282 2059 -276 321 -2018 319 -15984 341 -1984 343 -2016 2029 -298 2033 -258 309 -2028 321 -2032 2035 -284 2017 -298 337 -2008 289 -2034 2027 -314 2023 -310 285 -2016 321 -2014 2035 -282 2027 -308 317 -2026 297 -15982 357 -1984 345 -1982 2067 -264 2057 -258 341 -1996 317 -2026 2057 -282 2017 -318 325 -1972 319 -2018 2059 -280 2029 -302 315 -2006 319 -2006 2059 -274 2047 -276 307 +RAW_Data: -2024 311 -15984 349 -2004 317 -2012 2029 -276 2047 -312 305 -2018 311 -2018 2037 -258 2077 -258 337 -1998 321 -2026 2031 -278 2043 -284 327 -2020 311 -2018 2031 -278 2051 -288 325 -2004 323 -15962 353 -2018 317 -2014 2007 -308 2019 -320 287 -2024 325 -1998 2035 -314 2025 -302 311 -2004 319 -2010 2027 -312 2011 -310 309 -2028 303 -2018 2027 -304 2007 -294 309 -2024 323 -16002 361 -1946 347 -2008 2027 -286 2045 -312 325 -1978 319 -2024 2043 -276 2049 -286 325 -1988 341 -1978 2061 -278 2049 -284 327 -1990 321 -2020 2029 -318 2021 -278 323 -2008 321 -15990 355 -1982 355 -1984 2031 -284 2049 -278 325 -2018 321 -2000 2047 -276 2049 -286 327 -1994 341 -1976 2067 -274 2043 -284 303 -2018 341 -1982 2061 -266 2069 -258 339 -1998 321 -16002 311 -2014 329 -2012 2027 -318 1999 -298 339 -2008 287 -2042 2031 -282 2027 -306 317 -2012 291 -2044 2037 -284 2033 -302 315 -2004 321 -2012 2037 -282 2027 -306 317 -2028 297 -15980 345 -2018 285 -2026 2037 -320 2017 -278 323 -2024 299 -2002 2069 -278 2055 -286 325 -2002 289 -2024 2037 -282 2063 -276 321 -2016 287 -2036 2025 -320 2023 -278 323 -2018 287 -16006 355 -1982 355 -1986 2033 -302 2039 -282 307 -2032 309 -2014 2043 -264 2057 -258 341 -1992 319 -2036 2033 -284 2029 -306 319 -2000 319 -2014 2035 -282 2061 -266 343 -2006 289 -16018 331 -2010 313 -2014 2021 -320 2017 -278 323 -2010 321 -2016 2037 -284 2033 -304 317 -2018 287 -2036 2037 -284 2025 -296 339 -1978 321 -2028 2057 -282 2021 -278 359 -1972 321 -15990 355 -1978 355 -1990 2035 -300 2015 -312 305 -2016 315 -2016 2053 -290 2013 -316 277 -2020 353 -1980 2059 -256 2077 -276 307 -2020 311 -2012 2047 -258 2073 -256 341 -1998 321 -15976 369 -1976 313 -2018 2051 -280 2043 -290 317 -2004 321 -2024 2023 -282 2053 -282 327 -2020 313 -2020 2035 -278 2055 -284 325 -1986 321 -2016 2033 -280 2049 -282 325 -2020 313 -15986 315 -2026 319 -2028 2003 -318 2013 -294 339 -2008 289 -2032 2027 -316 2019 -302 311 -2004 321 -2014 2033 -314 1995 -308 317 -2028 297 -2032 2035 -276 2023 -316 321 -2014 289 -15998 347 -2014 283 -2020 2035 -292 2031 -288 311 -2024 321 -2036 2001 -310 2027 -318 275 -2054 277 -2026 2029 -296 2027 -292 311 -2024 321 -2030 2031 -282 2033 -304 313 -2004 321 -15992 329 -2010 349 -1980 2037 -292 2051 -256 339 -1998 319 -2034 2029 -286 2055 -264 339 -1978 321 -2030 2027 -280 2043 -316 327 -1984 315 -2016 2063 -278 2041 -288 327 -1990 325 -15964 389 -1978 319 -1984 2063 -256 2055 -292 307 -2016 323 -2028 2027 -286 2057 -274 319 -2010 319 -2010 2033 -282 2061 -276 321 -2018 289 -2032 2027 -318 2021 -278 321 -2020 319 -15974 355 -1980 357 -2000 2035 +RAW_Data: -254 2079 -276 309 -2016 309 -2012 2035 -296 2063 -258 337 -1992 321 -2030 2037 -286 2027 -294 333 -1978 321 -2034 2029 -286 2031 -306 315 -2008 321 -15972 355 -1984 315 -2014 2037 -310 2011 -318 323 -1984 329 -2002 2033 -316 2029 -278 323 -2026 299 -2030 2035 -278 2019 -316 325 -1980 323 -2018 2053 -252 2075 -280 327 -1984 355 -15954 345 -2008 309 -2016 2045 -266 2065 -258 341 -235740 101 -202 65 -734 133 -372 401 -68 269 -236 505 -68 235 -234 875 -68 13969 -100 14297 -70 3863 -96 59337 -104 11859 -68 17409 -68 7317 -66 11443 -64 15589 -66 4381 -98 32297 -168 45445 -100 59295 -100 41417 -66 1539 -66 23001 diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c new file mode 100644 index 000000000..e32679d27 --- /dev/null +++ b/lib/subghz/protocols/bett.c @@ -0,0 +1,357 @@ +#include "bett.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol BERNER / ELKA / TEDSEN / TELETASTER +#define TAG "SubGhzProtocolBETT" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c" +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0x8) >> 0x8) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_bett_const = { + .te_short = 340, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 18, +}; + +struct SubGhzProtocolDecoderBETT { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderBETT { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + BETTDecoderStepReset = 0, + BETTDecoderStepSaveDuration, + BETTDecoderStepCheckDuration, +} BETTDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_bett_decoder = { + .alloc = subghz_protocol_decoder_bett_alloc, + .free = subghz_protocol_decoder_bett_free, + + .feed = subghz_protocol_decoder_bett_feed, + .reset = subghz_protocol_decoder_bett_reset, + + .get_hash_data = subghz_protocol_decoder_bett_get_hash_data, + .serialize = subghz_protocol_decoder_bett_serialize, + .deserialize = subghz_protocol_decoder_bett_deserialize, + .get_string = subghz_protocol_decoder_bett_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_bett_encoder = { + .alloc = subghz_protocol_encoder_bett_alloc, + .free = subghz_protocol_encoder_bett_free, + + .deserialize = subghz_protocol_encoder_bett_deserialize, + .stop = subghz_protocol_encoder_bett_stop, + .yield = subghz_protocol_encoder_bett_yield, +}; + +const SubGhzProtocol subghz_protocol_bett = { + .name = SUBGHZ_PROTOCOL_BETT_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_bett_decoder, + .encoder = &subghz_protocol_bett_encoder, +}; + +void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderBETT* instance = malloc(sizeof(SubGhzProtocolEncoderBETT)); + + instance->base.protocol = &subghz_protocol_bett; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_bett_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBETT* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderBETT instance + * @return true On success + */ +static bool subghz_protocol_encoder_bett_get_upload(SubGhzProtocolEncoderBETT* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_bett_const.te_short + + subghz_protocol_bett_const.te_long * 7); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_bett_const.te_long + subghz_protocol_bett_const.te_long * 7); + } + return true; +} + +bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderBETT* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_bett_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_bett_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_bett_stop(void* context) { + SubGhzProtocolEncoderBETT* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_bett_yield(void* context) { + SubGhzProtocolEncoderBETT* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_bett_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderBETT* instance = malloc(sizeof(SubGhzProtocolDecoderBETT)); + instance->base.protocol = &subghz_protocol_bett; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_bett_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + free(instance); +} + +void subghz_protocol_decoder_bett_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + instance->decoder.parser_step = BETTDecoderStepReset; +} + +void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + + switch(instance->decoder.parser_step) { + case BETTDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 42) < + subghz_protocol_bett_const.te_delta * 21)) { + //Found Preambula + instance->decoder.parser_step = BETTDecoderStepCheckDuration; + } + break; + case BETTDecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_bett_const.te_short * 10 + + subghz_protocol_bett_const.te_delta)) { + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + if(instance->decoder.decode_count_bit == + subghz_protocol_bett_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + if((DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) < + subghz_protocol_bett_const.te_delta) || + (DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) < + subghz_protocol_bett_const.te_delta * 3)) { + instance->decoder.parser_step = BETTDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + } + } + break; + case BETTDecoderStepCheckDuration: + if(level) { + if(DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) < + subghz_protocol_bett_const.te_delta * 3) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) < + subghz_protocol_bett_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = BETTDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + } else { + instance->decoder.parser_step = BETTDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_bett_check_remote_controller(SubGhzBlockGeneric* instance) { + uint32_t code_found_reverse = + subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); + + instance->serial = (code_found_reverse & 0xFF) << 12 | + ((code_found_reverse >> 8) & 0xFF) << 4 | + ((code_found_reverse >> 20) & 0x0F); + instance->btn = ((code_found_reverse >> 16) & 0x0F); +} + +uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_bett_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_bett_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_bett_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderBETT* instance = context; + subghz_protocol_bett_check_remote_controller(&instance->generic); + uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%05lX\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data & 0xFFFFFF), + SHOW_DIP_P(data, DIP_P), + SHOW_DIP_P(data, DIP_O), + SHOW_DIP_P(data, DIP_N)); +} diff --git a/lib/subghz/protocols/bett.h b/lib/subghz/protocols/bett.h new file mode 100644 index 000000000..48f32b3e0 --- /dev/null +++ b/lib/subghz/protocols/bett.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_BETT_NAME "BETT" + +typedef struct SubGhzProtocolDecoderBETT SubGhzProtocolDecoderBETT; +typedef struct SubGhzProtocolEncoderBETT SubGhzProtocolEncoderBETT; + +extern const SubGhzProtocolDecoder subghz_protocol_bett_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_bett_encoder; +extern const SubGhzProtocol subghz_protocol_bett; + +/** + * Allocate SubGhzProtocolEncoderBETT. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderBETT* pointer to a SubGhzProtocolEncoderBETT instance + */ +void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderBETT. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + */ +void subghz_protocol_encoder_bett_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + */ +void subghz_protocol_encoder_bett_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderBETT instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_bett_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderBETT. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderBETT* pointer to a SubGhzProtocolDecoderBETT instance + */ +void* subghz_protocol_decoder_bett_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + */ +void subghz_protocol_decoder_bett_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + */ +void subghz_protocol_decoder_bett_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_bett_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderBETT. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderBETT instance + * @param output Resulting text + */ +void subghz_protocol_decoder_bett_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c new file mode 100644 index 000000000..c26cbc5b6 --- /dev/null +++ b/lib/subghz/protocols/doitrand.c @@ -0,0 +1,356 @@ +#include "doitrand.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolDoitrand" + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c" +#define CNT_TO_DIP(dip) \ + (dip & 0x0001 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \ + (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x1000 ? '1' : '0'), \ + (dip & 0x0800 ? '1' : '0'), (dip & 0x0400 ? '1' : '0'), (dip & 0x0200 ? '1' : '0'), \ + (dip & 0x0002 ? '1' : '0') + +static const SubGhzBlockConst subghz_protocol_doitrand_const = { + .te_short = 400, + .te_long = 1100, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct SubGhzProtocolDecoderDoitrand { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderDoitrand { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + DoitrandDecoderStepReset = 0, + DoitrandDecoderStepFoundStartBit, + DoitrandDecoderStepSaveDuration, + DoitrandDecoderStepCheckDuration, +} DoitrandDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder = { + .alloc = subghz_protocol_decoder_doitrand_alloc, + .free = subghz_protocol_decoder_doitrand_free, + + .feed = subghz_protocol_decoder_doitrand_feed, + .reset = subghz_protocol_decoder_doitrand_reset, + + .get_hash_data = subghz_protocol_decoder_doitrand_get_hash_data, + .serialize = subghz_protocol_decoder_doitrand_serialize, + .deserialize = subghz_protocol_decoder_doitrand_deserialize, + .get_string = subghz_protocol_decoder_doitrand_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder = { + .alloc = subghz_protocol_encoder_doitrand_alloc, + .free = subghz_protocol_encoder_doitrand_free, + + .deserialize = subghz_protocol_encoder_doitrand_deserialize, + .stop = subghz_protocol_encoder_doitrand_stop, + .yield = subghz_protocol_encoder_doitrand_yield, +}; + +const SubGhzProtocol subghz_protocol_doitrand = { + .name = SUBGHZ_PROTOCOL_DOITRAND_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_doitrand_decoder, + .encoder = &subghz_protocol_doitrand_encoder, +}; + +void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderDoitrand* instance = malloc(sizeof(SubGhzProtocolEncoderDoitrand)); + + instance->base.protocol = &subghz_protocol_doitrand; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_doitrand_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderDoitrand* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderDoitrand instance + * @return true On success + */ +static bool subghz_protocol_encoder_doitrand_get_upload(SubGhzProtocolEncoderDoitrand* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + //Send header + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short * 62); + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short * 2 - 100); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderDoitrand* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_doitrand_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_doitrand_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_doitrand_stop(void* context) { + SubGhzProtocolEncoderDoitrand* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_doitrand_yield(void* context) { + SubGhzProtocolEncoderDoitrand* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_doitrand_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderDoitrand* instance = malloc(sizeof(SubGhzProtocolDecoderDoitrand)); + instance->base.protocol = &subghz_protocol_doitrand; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_doitrand_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + free(instance); +} + +void subghz_protocol_decoder_doitrand_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + instance->decoder.parser_step = DoitrandDecoderStepReset; +} + +void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + + switch(instance->decoder.parser_step) { + case DoitrandDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short * 62) < + subghz_protocol_doitrand_const.te_delta * 30)) { + //Found Preambula + instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit; + } + break; + case DoitrandDecoderStepFoundStartBit: + if(level && ((DURATION_DIFF(duration, (subghz_protocol_doitrand_const.te_short * 2)) < + subghz_protocol_doitrand_const.te_delta * 3))) { + //Found start bit + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + break; + case DoitrandDecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_doitrand_const.te_short * 10 + + subghz_protocol_doitrand_const.te_delta)) { + instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit == + subghz_protocol_doitrand_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + instance->decoder.te_last = duration; + instance->decoder.parser_step = DoitrandDecoderStepCheckDuration; + } + } + break; + case DoitrandDecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_short) < + subghz_protocol_doitrand_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_long) < + subghz_protocol_doitrand_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_long) < + subghz_protocol_doitrand_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short) < + subghz_protocol_doitrand_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = DoitrandDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + } else { + instance->decoder.parser_step = DoitrandDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_doitrand_check_remote_controller(SubGhzBlockGeneric* instance) { + /* +* 67892345 0 k 1 +* 0000082F5F => 00000000000000000 10 000010111101011111 +* 0002082F5F => 00000000000100000 10 000010111101011111 +* 0200082F5F => 00010000000000000 10 000010111101011111 +* 0400082F5F => 00100000000000000 10 000010111101011111 +* 0800082F5F => 01000000000000000 10 000010111101011111 +* 1000082F5F => 10000000000000000 10 000010111101011111 +* 0020082F5F => 00000001000000000 10 000010111101011111 +* 0040082F5F => 00000010000000000 10 000010111101011111 +* 0080082F5F => 00000100000000000 10 000010111101011111 +* 0100082F5F => 00001000000000000 10 000010111101011111 +* 000008AF5F => 00000000000000000 10 001010111101011111 +* 1FE208AF5F => 11111111000100000 10 001010111101011111 +* +* 0...9 - DIP +* k- KEY +*/ + instance->cnt = (instance->data >> 24) | ((instance->data >> 15) & 0x1); + instance->btn = ((instance->data >> 18) & 0x3); +} + +uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_doitrand_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_doitrand_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderDoitrand* instance = context; + subghz_protocol_doitrand_check_remote_controller(&instance->generic); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%02lX%08lX\r\n" + "Btn:%lX\r\n" + "DIP:" DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.btn, + CNT_TO_DIP(instance->generic.cnt)); +} diff --git a/lib/subghz/protocols/doitrand.h b/lib/subghz/protocols/doitrand.h new file mode 100644 index 000000000..f94d73899 --- /dev/null +++ b/lib/subghz/protocols/doitrand.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_DOITRAND_NAME "Doitrand" + +typedef struct SubGhzProtocolDecoderDoitrand SubGhzProtocolDecoderDoitrand; +typedef struct SubGhzProtocolEncoderDoitrand SubGhzProtocolEncoderDoitrand; + +extern const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder; +extern const SubGhzProtocol subghz_protocol_doitrand; + +/** + * Allocate SubGhzProtocolEncoderDoitrand. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderDoitrand* pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderDoitrand. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void subghz_protocol_encoder_doitrand_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + */ +void subghz_protocol_encoder_doitrand_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_doitrand_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderDoitrand. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderDoitrand* pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void* subghz_protocol_decoder_doitrand_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void subghz_protocol_decoder_doitrand_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + */ +void subghz_protocol_decoder_doitrand_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_doitrand_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderDoitrand. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance + * @param output Resulting text + */ +void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index eeb240267..ed5e4fb54 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -359,7 +359,7 @@ void subghz_protocol_decoder_holtek_get_string(void* context, string_t output) { output, "%s %dbit\r\n" "Key:0x%lX%08lX\r\n" - "Sn:0x%05lX BTN:%X ", + "Sn:0x%05lX Btn:%X ", instance->generic.protocol_name, instance->generic.data_count_bit, (uint32_t)((instance->generic.data >> 32) & 0xFFFFFFFF), diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c new file mode 100644 index 000000000..d46927246 --- /dev/null +++ b/lib/subghz/protocols/marantec.c @@ -0,0 +1,393 @@ +#include "marantec.h" +#include +#include +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolMarantec" + +static const SubGhzBlockConst subghz_protocol_marantec_const = { + .te_short = 1000, + .te_long = 2000, + .te_delta = 200, + .min_count_bit_for_found = 49, +}; + +struct SubGhzProtocolDecoderMarantec { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + ManchesterState manchester_saved_state; + uint16_t header_count; +}; + +struct SubGhzProtocolEncoderMarantec { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + MarantecDecoderStepReset = 0, + MarantecDecoderFoundHeader, + MarantecDecoderStepDecoderData, +} MarantecDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_marantec_decoder = { + .alloc = subghz_protocol_decoder_marantec_alloc, + .free = subghz_protocol_decoder_marantec_free, + + .feed = subghz_protocol_decoder_marantec_feed, + .reset = subghz_protocol_decoder_marantec_reset, + + .get_hash_data = subghz_protocol_decoder_marantec_get_hash_data, + .serialize = subghz_protocol_decoder_marantec_serialize, + .deserialize = subghz_protocol_decoder_marantec_deserialize, + .get_string = subghz_protocol_decoder_marantec_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_marantec_encoder = { + .alloc = subghz_protocol_encoder_marantec_alloc, + .free = subghz_protocol_encoder_marantec_free, + + .deserialize = subghz_protocol_encoder_marantec_deserialize, + .stop = subghz_protocol_encoder_marantec_stop, + .yield = subghz_protocol_encoder_marantec_yield, +}; + +const SubGhzProtocol subghz_protocol_marantec = { + .name = SUBGHZ_PROTOCOL_MARANTEC_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_marantec_decoder, + .encoder = &subghz_protocol_marantec_encoder, +}; + +void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderMarantec* instance = malloc(sizeof(SubGhzProtocolEncoderMarantec)); + + instance->base.protocol = &subghz_protocol_marantec; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 256; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_marantec_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderMarantec* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static LevelDuration + subghz_protocol_encoder_marantec_add_duration_to_upload(ManchesterEncoderResult result) { + LevelDuration data = {.duration = 0, .level = 0}; + switch(result) { + case ManchesterEncoderResultShortLow: + data.duration = subghz_protocol_marantec_const.te_short; + data.level = false; + break; + case ManchesterEncoderResultLongLow: + data.duration = subghz_protocol_marantec_const.te_long; + data.level = false; + break; + case ManchesterEncoderResultLongHigh: + data.duration = subghz_protocol_marantec_const.te_long; + data.level = true; + break; + case ManchesterEncoderResultShortHigh: + data.duration = subghz_protocol_marantec_const.te_short; + data.level = true; + break; + + default: + furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); + break; + } + return level_duration_make(data.level, data.duration); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderMarantec instance + */ +static void subghz_protocol_encoder_marantec_get_upload(SubGhzProtocolEncoderMarantec* instance) { + furi_assert(instance); + size_t index = 0; + + ManchesterEncoderState enc_state; + manchester_encoder_reset(&enc_state); + ManchesterEncoderResult result; + + if(!manchester_encoder_advance( + &enc_state, + bit_read(instance->generic.data, instance->generic.data_count_bit - 1), + &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, + bit_read(instance->generic.data, instance->generic.data_count_bit - 1), + &result); + } + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_marantec_const.te_long * 5); + + for(uint8_t i = instance->generic.data_count_bit - 1; i > 0; i--) { + if(!manchester_encoder_advance( + &enc_state, bit_read(instance->generic.data, i - 1), &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, bit_read(instance->generic.data, i - 1), &result); + } + instance->encoder.upload[index++] = + subghz_protocol_encoder_marantec_add_duration_to_upload(result); + } + instance->encoder.upload[index] = subghz_protocol_encoder_marantec_add_duration_to_upload( + manchester_encoder_finish(&enc_state)); + if(level_duration_get_level(instance->encoder.upload[index])) { + index++; + } + instance->encoder.size_upload = index; +} + +uint8_t subghz_protocol_marantec_crc8(uint8_t* data, size_t len) { + uint8_t crc = 0x08; + size_t i, j; + for(i = 0; i < len; i++) { + crc ^= data[i]; + for(j = 0; j < 8; j++) { + if((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ 0x1D); + else + crc <<= 1; + } + } + return crc; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_marantec_remote_controller(SubGhzBlockGeneric* instance) { + instance->btn = (instance->data >> 16) & 0xF; + instance->serial = ((instance->data >> 12) & 0xFFFFFF00) | ((instance->data >> 8) & 0xFF); +} + +bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderMarantec* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_marantec_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_marantec_remote_controller(&instance->generic); + subghz_protocol_encoder_marantec_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_marantec_stop(void* context) { + SubGhzProtocolEncoderMarantec* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_marantec_yield(void* context) { + SubGhzProtocolEncoderMarantec* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_marantec_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderMarantec* instance = malloc(sizeof(SubGhzProtocolDecoderMarantec)); + instance->base.protocol = &subghz_protocol_marantec; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_marantec_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + free(instance); +} + +void subghz_protocol_decoder_marantec_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +void subghz_protocol_decoder_marantec_feed(void* context, bool level, volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + ManchesterEvent event = ManchesterEventReset; + + switch(instance->decoder.parser_step) { + case MarantecDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long * 5) < + subghz_protocol_marantec_const.te_delta * 8)) { + //Found header marantec + instance->decoder.parser_step = MarantecDecoderStepDecoderData; + instance->decoder.decode_data = 1; + instance->decoder.decode_count_bit = 1; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } + break; + case MarantecDecoderStepDecoderData: + if(!level) { + if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventShortLow; + } else if( + DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventLongLow; + } else if( + duration >= ((uint32_t)subghz_protocol_marantec_const.te_long * 2 + + subghz_protocol_marantec_const.te_delta)) { + if(instance->decoder.decode_count_bit == + subghz_protocol_marantec_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 1; + instance->decoder.decode_count_bit = 1; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } else { + instance->decoder.parser_step = MarantecDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventShortHigh; + } else if( + DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) < + subghz_protocol_marantec_const.te_delta) { + event = ManchesterEventLongHigh; + } else { + instance->decoder.parser_step = MarantecDecoderStepReset; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data; + instance->decoder.decode_count_bit++; + } + } + break; + } +} + +uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_marantec_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_marantec_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_marantec_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderMarantec* instance = context; + subghz_protocol_marantec_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->generic.btn); +} diff --git a/lib/subghz/protocols/marantec.h b/lib/subghz/protocols/marantec.h new file mode 100644 index 000000000..2da3c88a5 --- /dev/null +++ b/lib/subghz/protocols/marantec.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_MARANTEC_NAME "Marantec" + +typedef struct SubGhzProtocolDecoderMarantec SubGhzProtocolDecoderMarantec; +typedef struct SubGhzProtocolEncoderMarantec SubGhzProtocolEncoderMarantec; + +extern const SubGhzProtocolDecoder subghz_protocol_marantec_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_marantec_encoder; +extern const SubGhzProtocol subghz_protocol_marantec; + +/** + * Allocate SubGhzProtocolEncoderMarantec. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderMarantec* pointer to a SubGhzProtocolEncoderMarantec instance + */ +void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderMarantec. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + */ +void subghz_protocol_encoder_marantec_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + */ +void subghz_protocol_encoder_marantec_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderMarantec instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_marantec_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderMarantec. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderMarantec* pointer to a SubGhzProtocolDecoderMarantec instance + */ +void* subghz_protocol_decoder_marantec_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + */ +void subghz_protocol_decoder_marantec_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + */ +void subghz_protocol_decoder_marantec_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_marantec_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_marantec_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderMarantec. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderMarantec instance + * @param output Resulting text + */ +void subghz_protocol_decoder_marantec_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c new file mode 100644 index 000000000..e71e28349 --- /dev/null +++ b/lib/subghz/protocols/phoenix_v2.c @@ -0,0 +1,339 @@ +#include "phoenix_v2.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolPhoenix_V2" + +//transmission only static mode + +static const SubGhzBlockConst subghz_protocol_phoenix_v2_const = { + .te_short = 427, + .te_long = 853, + .te_delta = 100, + .min_count_bit_for_found = 52, +}; + +struct SubGhzProtocolDecoderPhoenix_V2 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderPhoenix_V2 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + Phoenix_V2DecoderStepReset = 0, + Phoenix_V2DecoderStepFoundStartBit, + Phoenix_V2DecoderStepSaveDuration, + Phoenix_V2DecoderStepCheckDuration, +} Phoenix_V2DecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder = { + .alloc = subghz_protocol_decoder_phoenix_v2_alloc, + .free = subghz_protocol_decoder_phoenix_v2_free, + + .feed = subghz_protocol_decoder_phoenix_v2_feed, + .reset = subghz_protocol_decoder_phoenix_v2_reset, + + .get_hash_data = subghz_protocol_decoder_phoenix_v2_get_hash_data, + .serialize = subghz_protocol_decoder_phoenix_v2_serialize, + .deserialize = subghz_protocol_decoder_phoenix_v2_deserialize, + .get_string = subghz_protocol_decoder_phoenix_v2_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder = { + .alloc = subghz_protocol_encoder_phoenix_v2_alloc, + .free = subghz_protocol_encoder_phoenix_v2_free, + + .deserialize = subghz_protocol_encoder_phoenix_v2_deserialize, + .stop = subghz_protocol_encoder_phoenix_v2_stop, + .yield = subghz_protocol_encoder_phoenix_v2_yield, +}; + +const SubGhzProtocol subghz_protocol_phoenix_v2 = { + .name = SUBGHZ_PROTOCOL_PHOENIX_V2_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_phoenix_v2_decoder, + .encoder = &subghz_protocol_phoenix_v2_encoder, +}; + +void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolEncoderPhoenix_V2)); + + instance->base.protocol = &subghz_protocol_phoenix_v2; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_phoenix_v2_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderPhoenix_V2* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @return true On success + */ +static bool + subghz_protocol_encoder_phoenix_v2_get_upload(SubGhzProtocolEncoderPhoenix_V2* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + //Send header + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 60); + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 6); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(!bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderPhoenix_V2* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_phoenix_v2_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_phoenix_v2_stop(void* context) { + SubGhzProtocolEncoderPhoenix_V2* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context) { + SubGhzProtocolEncoderPhoenix_V2* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolDecoderPhoenix_V2)); + instance->base.protocol = &subghz_protocol_phoenix_v2; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_phoenix_v2_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + free(instance); +} + +void subghz_protocol_decoder_phoenix_v2_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; +} + +void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + + switch(instance->decoder.parser_step) { + case Phoenix_V2DecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short * 60) < + subghz_protocol_phoenix_v2_const.te_delta * 30)) { + //Found Preambula + instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit; + } + break; + case Phoenix_V2DecoderStepFoundStartBit: + if(level && ((DURATION_DIFF(duration, (subghz_protocol_phoenix_v2_const.te_short * 6)) < + subghz_protocol_phoenix_v2_const.te_delta * 4))) { + //Found start bit + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + break; + case Phoenix_V2DecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_phoenix_v2_const.te_short * 10 + + subghz_protocol_phoenix_v2_const.te_delta)) { + instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit == + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; + } else { + instance->decoder.te_last = duration; + instance->decoder.parser_step = Phoenix_V2DecoderStepCheckDuration; + } + } + break; + case Phoenix_V2DecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_short) < + subghz_protocol_phoenix_v2_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_long) < + subghz_protocol_phoenix_v2_const.te_delta * 3)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_long) < + subghz_protocol_phoenix_v2_const.te_delta * 3) && + (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short) < + subghz_protocol_phoenix_v2_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + } else { + instance->decoder.parser_step = Phoenix_V2DecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_phoenix_v2_check_remote_controller(SubGhzBlockGeneric* instance) { + uint64_t data_rev = + subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit + 4); + instance->serial = data_rev & 0xFFFFFFFF; + instance->cnt = (data_rev >> 40) & 0xFFFF; + instance->btn = (data_rev >> 32) & 0xF; +} + +uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_phoenix_v2_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_phoenix_v2_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderPhoenix_V2* instance = context; + subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic); + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%02lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF, + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->generic.btn); +} diff --git a/lib/subghz/protocols/phoenix_v2.h b/lib/subghz/protocols/phoenix_v2.h new file mode 100644 index 000000000..38cadc1a2 --- /dev/null +++ b/lib/subghz/protocols/phoenix_v2.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_PHOENIX_V2_NAME "Phoenix_V2" + +typedef struct SubGhzProtocolDecoderPhoenix_V2 SubGhzProtocolDecoderPhoenix_V2; +typedef struct SubGhzProtocolEncoderPhoenix_V2 SubGhzProtocolEncoderPhoenix_V2; + +extern const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder; +extern const SubGhzProtocol subghz_protocol_phoenix_v2; + +/** + * Allocate SubGhzProtocolEncoderPhoenix_V2. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderPhoenix_V2* pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void subghz_protocol_encoder_phoenix_v2_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + */ +void subghz_protocol_encoder_phoenix_v2_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderPhoenix_V2. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderPhoenix_V2* pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void* subghz_protocol_decoder_phoenix_v2_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void subghz_protocol_decoder_phoenix_v2_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + */ +void subghz_protocol_decoder_phoenix_v2_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_phoenix_v2_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderPhoenix_V2. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 0f1001372..3fdeaae94 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -256,8 +256,6 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; - instance->generic.serial = instance->decoder.decode_data >> 4; - instance->generic.btn = (uint8_t)instance->decoder.decode_data & 0x00000F; if(instance->base.callback) instance->base.callback(&instance->base, instance->base.context); @@ -295,6 +293,15 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t } } +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_princeton_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = instance->data >> 4; + instance->btn = instance->data & 0xF; +} + uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; @@ -347,25 +354,21 @@ bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* void subghz_protocol_decoder_princeton_get_string(void* context, string_t output) { furi_assert(context); SubGhzProtocolDecoderPrinceton* instance = context; - - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - - uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( + subghz_protocol_princeton_check_remote_controller(&instance->generic); + uint32_t data_rev = subghz_protocol_blocks_reverse_key( instance->generic.data, instance->generic.data_count_bit); - uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; - string_cat_printf( output, "%s %dbit\r\n" "Key:0x%08lX\r\n" "Yek:0x%08lX\r\n" - "Sn:0x%05lX BTN:%02X\r\n" + "Sn:0x%05lX Btn:%01X\r\n" "Te:%dus\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, - code_found_lo, - code_found_reverse_lo, + (uint32_t)(instance->generic.data & 0xFFFFFF), + data_rev, instance->generic.serial, instance->generic.btn, instance->te); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 5a09ee8c2..893947304 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -9,7 +9,8 @@ const SubGhzProtocol* subghz_protocol_registry[] = { &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, &subghz_protocol_power_smart, + &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, + &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index d64b0cddc..97a1376d6 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -28,6 +28,10 @@ #include "holtek.h" #include "chamberlain_code.h" #include "power_smart.h" +#include "marantec.h" +#include "bett.h" +#include "doitrand.h" +#include "phoenix_v2.h" /** * Registration by name SubGhzProtocol. From a7316e7822900f1c4adb806b7b73b36f01937aa6 Mon Sep 17 00:00:00 2001 From: Oleg K Date: Sun, 7 Aug 2022 19:08:00 +0300 Subject: [PATCH 07/26] Added support for Samsung TVs using address 07. (#1509) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added support for Samsung TVs using address 07. Samsung QEXX, UEXX * Recompile assets and update manifest Co-authored-by: あく --- assets/resources/Manifest | 4 +-- assets/resources/infrared/assets/tv.ir | 36 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index b353e3426..7dbd077be 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1658906571 +T:1659888302 D:badusb D:dolphin D:infrared @@ -223,7 +223,7 @@ F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt D:infrared/assets -F:d895fda2f48c6cc4c55e8a398ff52e43:74300:infrared/assets/tv.ir +F:a565c3a381695a5f2ba7a0698460238c:74833:infrared/assets/tv.ir F:a157a80f5a668700403d870c23b9567d:470:music_player/Marble_Machine.fmf D:nfc/assets F:81dc04c7b181f94b644079a71476dff4:4742:nfc/assets/aid.nfc diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index 98292a8ec..79478e7eb 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -135,6 +135,42 @@ command: 02 00 00 00 # name: POWER type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: E6 00 00 00 +# +name: VOL+ +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 07 00 00 00 +# +name: VOL- +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0B 00 00 00 +# +name: CH+ +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 12 00 00 00 +# +name: CH- +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 10 00 00 00 +# +name: MUTE +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0F 00 00 00 +# +name: POWER +type: parsed protocol: NEC address: 50 00 00 00 command: 17 00 00 00 From ca23d0c207a2ac2f52885686e61f893d332c515f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 9 Aug 2022 15:16:09 +0300 Subject: [PATCH 08/26] fix building updater package (#1564) --- .vscode/example/tasks.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index c124305cb..32efa0068 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -55,13 +55,13 @@ "label": "[Release] Build update bundle", "group": "build", "type": "shell", - "command": "./fbt update_package COMPACT=1 DEBUG=0" + "command": "./fbt updater_package COMPACT=1 DEBUG=0" }, { "label": "[Debug] Build update bundle", "group": "build", "type": "shell", - "command": "./fbt update_package" + "command": "./fbt updater_package" }, { "label": "[Release] Build updater", From 01eb92db0695fe73f8866580af36cc03362d297c Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Tue, 9 Aug 2022 18:45:52 +0300 Subject: [PATCH 09/26] Mifare Classic emulation fixes (#1566) * Add fix for field * More small bugfixes * Clean up --- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 7 +++++-- lib/nfc/protocols/mifare_classic.c | 18 +++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 7b7d5f275..2d6db8fbf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -341,13 +341,13 @@ void furi_hal_nfc_listen_start(FuriHalNfcDevData* nfc_data) { if(nfc_data->uid_len == 4) { pt_memory[12] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE; } else { - pt_memory[12] = nfc_data->sak | FURI_HAL_NFC_UID_INCOMPLETE; + pt_memory[12] = FURI_HAL_NFC_UID_INCOMPLETE; } pt_memory[13] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE; pt_memory[14] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE; st25r3916WritePTMem(pt_memory, sizeof(pt_memory)); - // Go to sence + // Go to sense st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SENSE); } @@ -507,6 +507,9 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ uint8_t rxe = 0; uint32_t start = DWT->CYCCNT; while(true) { + if(!rfalIsExtFieldOn()) { + return false; + } if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) { st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe); if(rxe & (1 << 4)) { diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 44b783d6d..3b5343932 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -771,6 +771,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // Read command while(!command_processed) { if(!is_encrypted) { + crypto1_reset(&emulator->crypto); memcpy(plain_data, tx_rx->rx_data, tx_rx->rx_bits / 8); } else { if(!furi_hal_nfc_tx_rx(tx_rx, 300)) { @@ -803,7 +804,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ access_key = MfClassicKeyB; } - uint32_t nonce = prng_successor(DWT->CYCCNT, 32); + uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA; uint8_t nt[4]; uint8_t nt_keystream[4]; nfc_util_num2bytes(nonce, 4, nt); @@ -858,7 +859,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0); if(cardRr != prng_successor(nonce, 64)) { FURI_LOG_T(TAG, "Wrong AUTH! %08X != %08X", cardRr, prng_successor(nonce, 64)); - // Don't send NACK, as tag don't send it + // Don't send NACK, as the tag doesn't send it command_processed = true; break; } @@ -897,7 +898,18 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } else { if(!mf_classic_is_allowed_access( emulator, block, access_key, MfClassicActionDataRead)) { - memset(block_data, 0, 16); + // Send NACK + uint8_t nack = 0x04; + if(is_encrypted) { + mf_crypto1_encrypt( + &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); + } else { + tx_rx->tx_data[0] = nack; + } + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_bits = 4; + furi_hal_nfc_tx_rx(tx_rx, 300); + break; } } nfca_append_crc16(block_data, 16); From 1d50a5981e818e6033512fb6bd633a181aef9539 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 9 Aug 2022 18:57:11 +0300 Subject: [PATCH 10/26] [FL-2059] Storage fixes for handling empty files (#1563) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * storage: fixed handling of zero-length files * docs: added ReadMe.md for vscode workspace * rpc: storage: improved empty file & error handling in write handler * docs: markdown fix * docs: typo fixes Co-authored-by: SG Co-authored-by: あく --- .vscode/ReadMe.md | 17 ++++++++ applications/rpc/rpc_storage.c | 64 +++++++++++++++++------------- applications/storage/storage_cli.c | 44 ++++++++++---------- lib/toolbox/path.c | 4 ++ 4 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 .vscode/ReadMe.md diff --git a/.vscode/ReadMe.md b/.vscode/ReadMe.md new file mode 100644 index 000000000..5aed0435c --- /dev/null +++ b/.vscode/ReadMe.md @@ -0,0 +1,17 @@ +# Visual Studio Code workspace for Flipper Zero + +## Setup + + * To start developing with VSCode, run `./fbt vscode_dist` in project root. _That should only be done once_ + * After that, open firmware folder in VSCode: "File" > "Open folder" + + For more details on fbt, see [fbt docs](../documentation/fbt.md). + + +## Workflow + +Commands for building firmware are invoked through Build menu: Ctrl+Shift+B. + +To attach a debugging session, first build and flash firmware, then choose your debug probe in Debug menu (Ctrl+Shift+D). + +Note that you have to detach debugging session before rebuilding and re-flashing firmware. diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index 1e2920f5b..48ea9e998 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -305,21 +305,27 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex response->command_id = request->command_id; response->which_content = PB_Main_storage_read_response_tag; response->command_status = PB_CommandStatus_OK; - response->content.storage_read_response.has_file = true; - response->content.storage_read_response.file.data = - malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(MIN(size_left, MAX_DATA_SIZE))); - uint8_t* buffer = response->content.storage_read_response.file.data->bytes; - uint16_t* read_size_msg = &response->content.storage_read_response.file.data->size; size_t read_size = MIN(size_left, MAX_DATA_SIZE); - *read_size_msg = storage_file_read(file, buffer, read_size); - size_left -= read_size; - result = (*read_size_msg == read_size); + if(read_size) { + response->content.storage_read_response.has_file = true; + response->content.storage_read_response.file.data = + malloc(PB_BYTES_ARRAY_T_ALLOCSIZE()); + uint8_t* buffer = response->content.storage_read_response.file.data->bytes; + uint16_t* read_size_msg = &response->content.storage_read_response.file.data->size; - if(result) { - response->has_next = (size_left > 0); - rpc_send_and_release(session, response); + *read_size_msg = storage_file_read(file, buffer, read_size); + size_left -= read_size; + result = (*read_size_msg == read_size); + + response->has_next = result && (size_left > 0); + } else { + response->content.storage_read_response.has_file = false; + response->has_next = false; + result = true; } + + rpc_send_and_release(session, response); } while((size_left != 0) && result); if(!result) { @@ -349,7 +355,7 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte RpcSession* session = rpc_storage->session; furi_assert(session); - bool result = true; + bool fs_operation_success = true; if(!path_contains_only_ascii(request->content.storage_write_request.path)) { rpc_storage->current_command_id = request->command_id; @@ -370,28 +376,32 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte rpc_storage->current_command_id = request->command_id; rpc_storage->state = RpcStorageStateWriting; const char* path = request->content.storage_write_request.path; - result = storage_file_open(rpc_storage->file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS); + fs_operation_success = + storage_file_open(rpc_storage->file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS); } File* file = rpc_storage->file; + bool send_response = false; - if(result) { - uint8_t* buffer = request->content.storage_write_request.file.data->bytes; - size_t buffer_size = request->content.storage_write_request.file.data->size; - - uint16_t written_size = storage_file_write(file, buffer, buffer_size); - result = (written_size == buffer_size); - - if(result && !request->has_next) { - rpc_send_and_release_empty( - session, rpc_storage->current_command_id, PB_CommandStatus_OK); - rpc_system_storage_reset_state(rpc_storage, session, false); + if(fs_operation_success) { + if(request->content.storage_write_request.has_file) { + uint8_t* buffer = request->content.storage_write_request.file.data->bytes; + size_t buffer_size = request->content.storage_write_request.file.data->size; + uint16_t written_size = storage_file_write(file, buffer, buffer_size); + fs_operation_success = (written_size == buffer_size); } + + send_response = !request->has_next; } - if(!result) { - rpc_send_and_release_empty( - session, rpc_storage->current_command_id, rpc_system_storage_get_file_error(file)); + PB_CommandStatus command_status = PB_CommandStatus_OK; + if(!fs_operation_success) { + send_response = true; + command_status = rpc_system_storage_get_file_error(file); + } + + if(send_response) { + rpc_send_and_release_empty(session, rpc_storage->current_command_id, command_status); rpc_system_storage_reset_state(rpc_storage, session, false); } } diff --git a/applications/storage/storage_cli.c b/applications/storage/storage_cli.c index fd988da76..802ebd548 100644 --- a/applications/storage/storage_cli.c +++ b/applications/storage/storage_cli.c @@ -274,24 +274,26 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) { if(parsed_count == EOF || parsed_count != 1) { storage_cli_print_usage(); } else if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - uint8_t* data = malloc(buffer_size); uint64_t file_size = storage_file_size(file); printf("Size: %lu\r\n", (uint32_t)file_size); - while(file_size > 0) { - printf("\r\nReady?\r\n"); - cli_getc(cli); + if(buffer_size) { + uint8_t* data = malloc(buffer_size); + while(file_size > 0) { + printf("\r\nReady?\r\n"); + cli_getc(cli); - uint16_t read_size = storage_file_read(file, data, buffer_size); - for(uint16_t i = 0; i < read_size; i++) { - putchar(data[i]); + uint16_t read_size = storage_file_read(file, data, buffer_size); + for(uint16_t i = 0; i < read_size; i++) { + putchar(data[i]); + } + file_size -= read_size; } - file_size -= read_size; + free(data); } printf("\r\n"); - free(data); } else { storage_cli_print_error(storage_file_get_error(file)); } @@ -315,19 +317,21 @@ static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) { if(storage_file_open(file, string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) { printf("Ready\r\n"); - uint8_t* buffer = malloc(buffer_size); + if(buffer_size) { + uint8_t* buffer = malloc(buffer_size); - for(uint32_t i = 0; i < buffer_size; i++) { - buffer[i] = cli_getc(cli); + for(uint32_t i = 0; i < buffer_size; i++) { + buffer[i] = cli_getc(cli); + } + + uint16_t written_size = storage_file_write(file, buffer, buffer_size); + + if(written_size != buffer_size) { + storage_cli_print_error(storage_file_get_error(file)); + } + + free(buffer); } - - uint16_t written_size = storage_file_write(file, buffer, buffer_size); - - if(written_size != buffer_size) { - storage_cli_print_error(storage_file_get_error(file)); - } - - free(buffer); } else { storage_cli_print_error(storage_file_get_error(file)); } diff --git a/lib/toolbox/path.c b/lib/toolbox/path.c index 38af1efe5..1262362ef 100644 --- a/lib/toolbox/path.c +++ b/lib/toolbox/path.c @@ -85,6 +85,10 @@ void path_concat(const char* path, const char* suffix, string_t out_path) { } bool path_contains_only_ascii(const char* path) { + if(!path) { + return false; + } + const char* name_pos = strrchr(path, '/'); if(name_pos == NULL) { name_pos = path; From add2497a1cfdee50ff1cb8c6e24ad4f23f4ad851 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 11 Aug 2022 11:28:57 +0300 Subject: [PATCH 11/26] rpc: additional verification of message data (#1576) * rpc: additional verification of message data * rpc: storage: fixed read handler * acessor: fixed record naming --- applications/accessor/accessor_app.cpp | 4 +-- .../accessor/accessor_view_manager.cpp | 3 +- applications/rpc/rpc_storage.c | 31 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/applications/accessor/accessor_app.cpp b/applications/accessor/accessor_app.cpp index f021a816e..2e3e27ec4 100644 --- a/applications/accessor/accessor_app.cpp +++ b/applications/accessor/accessor_app.cpp @@ -32,14 +32,14 @@ void AccessorApp::run(void) { } AccessorApp::AccessorApp() { - notification = static_cast(furi_record_open("notification")); + notification = static_cast(furi_record_open(RECORD_NOTIFICATION)); onewire_host = onewire_host_alloc(); furi_hal_power_enable_otg(); } AccessorApp::~AccessorApp() { furi_hal_power_disable_otg(); - furi_record_close("notification"); + furi_record_close(RECORD_NOTIFICATION); onewire_host_free(onewire_host); } diff --git a/applications/accessor/accessor_view_manager.cpp b/applications/accessor/accessor_view_manager.cpp index 7c681cbba..db723d68c 100644 --- a/applications/accessor/accessor_view_manager.cpp +++ b/applications/accessor/accessor_view_manager.cpp @@ -15,7 +15,7 @@ AccessorAppViewManager::AccessorAppViewManager() { popup = popup_alloc(); add_view(ViewType::Popup, popup_get_view(popup)); - gui = static_cast(furi_record_open("gui")); + gui = static_cast(furi_record_open(RECORD_GUI)); view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); // set previous view callback for all views @@ -31,6 +31,7 @@ AccessorAppViewManager::~AccessorAppViewManager() { view_dispatcher, static_cast(AccessorAppViewManager::ViewType::Popup)); // free view modules + furi_record_close(RECORD_GUI); submenu_free(submenu); popup_free(popup); diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index 48ea9e998..468e1e08e 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -297,9 +297,9 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex const char* path = request->content.storage_read_request.path; Storage* fs_api = furi_record_open(RECORD_STORAGE); File* file = storage_file_alloc(fs_api); - bool result = false; + bool fs_operation_success = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); - if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) { + if(fs_operation_success) { size_t size_left = storage_file_size(file); do { response->command_id = request->command_id; @@ -310,28 +310,25 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex if(read_size) { response->content.storage_read_response.has_file = true; response->content.storage_read_response.file.data = - malloc(PB_BYTES_ARRAY_T_ALLOCSIZE()); - uint8_t* buffer = response->content.storage_read_response.file.data->bytes; + malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(read_size)); + uint8_t* buffer = &response->content.storage_read_response.file.data->bytes[0]; uint16_t* read_size_msg = &response->content.storage_read_response.file.data->size; *read_size_msg = storage_file_read(file, buffer, read_size); - size_left -= read_size; - result = (*read_size_msg == read_size); + size_left -= *read_size_msg; + fs_operation_success = (*read_size_msg == read_size); - response->has_next = result && (size_left > 0); + response->has_next = fs_operation_success && (size_left > 0); } else { response->content.storage_read_response.has_file = false; response->has_next = false; - result = true; + fs_operation_success = true; } + } while((size_left != 0) && fs_operation_success); + } - rpc_send_and_release(session, response); - } while((size_left != 0) && result); - - if(!result) { - rpc_send_and_release_empty( - session, request->command_id, rpc_system_storage_get_file_error(file)); - } + if(fs_operation_success) { + rpc_send_and_release(session, response); } else { rpc_send_and_release_empty( session, request->command_id, rpc_system_storage_get_file_error(file)); @@ -384,7 +381,9 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte bool send_response = false; if(fs_operation_success) { - if(request->content.storage_write_request.has_file) { + if(request->content.storage_write_request.has_file && + request->content.storage_write_request.file.data && + request->content.storage_write_request.file.data->size) { uint8_t* buffer = request->content.storage_write_request.file.data->bytes; size_t buffer_size = request->content.storage_write_request.file.data->size; uint16_t written_size = storage_file_write(file, buffer, buffer_size); From fae392d84eaa3f50d78e8d1b7fc3b19ac6f3c3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 11 Aug 2022 18:21:56 +0900 Subject: [PATCH 12/26] [FL-2677] SubGhz: region provisioning (#1574) * FuriHal: region HAL draft * FuriHal,SubGhz: complete region provisioning. * Rpc: fix null pointer dereference. * Cli: device info formatting * FuriHal: region provisioning fixes and documentation. --- applications/cli/cli_commands.c | 2 +- applications/loader/application.fam | 2 +- applications/subghz/subghz_cli.c | 95 +++++++++++- applications/subghz/subghz_i.c | 2 +- assets/protobuf | 2 +- firmware/targets/f7/furi_hal/furi_hal.c | 1 + firmware/targets/f7/furi_hal/furi_hal_info.c | 8 +- .../targets/f7/furi_hal/furi_hal_region.c | 135 ++++++++++++++++++ .../targets/f7/furi_hal/furi_hal_subghz.c | 47 +----- firmware/targets/furi_hal_include/furi_hal.h | 1 + .../furi_hal_include/furi_hal_region.h | 73 ++++++++++ .../furi_hal_include/furi_hal_subghz.h | 8 -- lib/subghz/subghz_tx_rx_worker.c | 2 +- 13 files changed, 318 insertions(+), 60 deletions(-) create mode 100644 firmware/targets/f7/furi_hal/furi_hal_region.c create mode 100644 firmware/targets/furi_hal_include/furi_hal_region.h diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 198877962..177a274a1 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -15,7 +15,7 @@ void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { UNUSED(context); UNUSED(last); - printf("%-24s: %s\r\n", key, value); + printf("%-30s: %s\r\n", key, value); } /* diff --git a/applications/loader/application.fam b/applications/loader/application.fam index 16351f8d1..c1ba4e549 100644 --- a/applications/loader/application.fam +++ b/applications/loader/application.fam @@ -5,6 +5,6 @@ App( entry_point="loader_srv", cdefines=["SRV_LOADER"], requires=["gui"], - stack_size=1 * 1024, + stack_size=2 * 1024, order=90, ) diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 2b6fdd841..09dae0481 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -16,9 +16,14 @@ #include #include +#include +#include + #define SUBGHZ_FREQUENCY_RANGE_STR \ "299999755...348000000 or 386999938...464000000 or 778999847...928000000" +#define SUBGHZ_REGION_FILENAME "/int/.region_data" + void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) { UNUSED(context); uint32_t frequency = 433920000; @@ -533,7 +538,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { return; } } - if(!furi_hal_subghz_is_tx_allowed(frequency)) { + if(!furi_hal_region_is_frequency_allowed(frequency)) { printf( "In your region, only reception on this frequency (%lu) is allowed,\r\n" "the actual operation of the application is not possible\r\n ", @@ -756,6 +761,46 @@ static void subghz_cli_command(Cli* cli, string_t args, void* context) { string_clear(cmd); } +static bool + subghz_on_system_start_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { + File* file = istream->state; + uint16_t ret = storage_file_read(file, buf, count); + return (count == ret); +} + +static bool subghz_on_system_start_istream_decode_band( + pb_istream_t* stream, + const pb_field_t* field, + void** arg) { + (void)field; + FuriHalRegion* region = *arg; + + PB_Region_Band band = {0}; + if(!pb_decode(stream, PB_Region_Band_fields, &band)) { + FURI_LOG_E("SubGhzOnStart", "PB Region band decode error: %s", PB_GET_ERROR(stream)); + return false; + } + + region->bands_count += 1; + region = + realloc(region, sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); + size_t pos = region->bands_count - 1; + region->bands[pos].start = band.start; + region->bands[pos].end = band.end; + region->bands[pos].power_limit = band.power_limit; + region->bands[pos].duty_cycle = band.duty_cycle; + *arg = region; + + FURI_LOG_I( + "SubGhzOnStart", + "Add allowed band: start %dHz, stop %dHz, power_limit %ddBm, duty_cycle %d%%", + band.start, + band.end, + band.power_limit, + band.duty_cycle); + return true; +} + void subghz_on_system_start() { #ifdef SRV_CLI Cli* cli = furi_record_open(RECORD_CLI); @@ -766,4 +811,52 @@ void subghz_on_system_start() { #else UNUSED(subghz_cli_command); #endif + +#ifdef SRV_STORAGE + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + FileInfo fileinfo = {0}; + PB_Region pb_region = {0}; + pb_region.bands.funcs.decode = subghz_on_system_start_istream_decode_band; + + do { + if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK || + fileinfo.size == 0) { + FURI_LOG_W("SubGhzOnStart", "Region data is missing or empty"); + break; + } + + if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E("SubGhzOnStart", "Unable to open region data"); + break; + } + + pb_istream_t istream = { + .callback = subghz_on_system_start_istream_read, + .state = file, + .errmsg = NULL, + .bytes_left = fileinfo.size, + }; + + pb_region.bands.arg = malloc(sizeof(FuriHalRegion)); + if(!pb_decode(&istream, PB_Region_fields, &pb_region)) { + FURI_LOG_E("SubGhzOnStart", "Invalid region data"); + free(pb_region.bands.arg); + break; + } + + FuriHalRegion* region = pb_region.bands.arg; + memcpy( + region->country_code, + pb_region.country_code->bytes, + pb_region.country_code->size < 4 ? pb_region.country_code->size : 3); + furi_hal_region_set(region); + } while(0); + + pb_release(PB_Region_fields, &pb_region); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); +#else + UNUSED(subghz_cli_command); +#endif } diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 00cc922c7..b08b658a4 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -278,7 +278,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + if(!furi_hal_region_is_frequency_allowed(temp_data32)) { FURI_LOG_E(TAG, "This frequency can only be used for RX in your region"); load_key_state = SubGhzLoadKeyStateOnlyRx; break; diff --git a/assets/protobuf b/assets/protobuf index cc5918dc4..6727eaf28 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit cc5918dc488ac3617012ce5377114e086b447324 +Subproject commit 6727eaf287db077dcd28719cd764f5804712223e diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 23f409736..d0856127a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -49,6 +49,7 @@ void furi_hal_init() { FURI_LOG_I(TAG, "GPIO OK"); furi_hal_version_init(); + furi_hal_region_init(); furi_hal_spi_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index cf7140eb4..1f75ea331 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -1,6 +1,11 @@ #include -#include +#include +#include +#include +#include + #include +#include #include void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { @@ -45,6 +50,7 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { out("hardware_color", string_get_cstr(value), false, context); string_printf(value, "%d", furi_hal_version_get_hw_region()); out("hardware_region", string_get_cstr(value), false, context); + out("hardware_region_provisioned", furi_hal_region_get_name(), false, context); const char* name = furi_hal_version_get_name_ptr(); if(name) { out("hardware_name", name, false, context); diff --git a/firmware/targets/f7/furi_hal/furi_hal_region.c b/firmware/targets/f7/furi_hal/furi_hal_region.c new file mode 100644 index 000000000..143d5c18c --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_region.c @@ -0,0 +1,135 @@ +#include +#include + +const FuriHalRegion furi_hal_region_zero = { + .country_code = "00", + .bands_count = 1, + .bands = { + { + .start = 0, + .end = 1000000000, + .power_limit = 12, + .duty_cycle = 50, + }, + }}; + +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; +} + +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) { + if(!furi_hal_region) { + return false; + } + + const FuriHalRegionBand* band = furi_hal_region_get_band(frequency); + if(!band) { + return false; + } + + return true; +} + +const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency) { + if(!furi_hal_region) { + return NULL; + } + + for(size_t i = 0; i < furi_hal_region->bands_count; i++) { + if(furi_hal_region->bands[i].start <= frequency && + furi_hal_region->bands[i].end >= frequency) { + return &furi_hal_region->bands[i]; + } + } + + return NULL; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 650f8ac33..ade462389 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -1,6 +1,7 @@ #include "furi_hal_subghz.h" #include "furi_hal_subghz_configs.h" +#include #include #include #include @@ -308,52 +309,8 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { return value; } -bool furi_hal_subghz_is_tx_allowed(uint32_t value) { - //checking regional settings - bool is_allowed = false; - switch(furi_hal_version_get_hw_region()) { - 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 >= 304100000 && 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; - } - return is_allowed; -} - uint32_t furi_hal_subghz_set_frequency(uint32_t value) { - if(furi_hal_subghz_is_tx_allowed(value)) { + if(furi_hal_region_is_frequency_allowed(value)) { furi_hal_subghz.regulation = SubGhzRegulationTxRx; } else { furi_hal_subghz.regulation = SubGhzRegulationOnlyRx; diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 4d1fc9704..2a372a6c3 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -18,6 +18,7 @@ template struct STOP_EXTERNING_ME {}; #include "furi_hal_sd.h" #include "furi_hal_i2c.h" #include "furi_hal_resources.h" +#include "furi_hal_region.h" #include "furi_hal_rtc.h" #include "furi_hal_speaker.h" #include "furi_hal_gpio.h" diff --git a/firmware/targets/furi_hal_include/furi_hal_region.h b/firmware/targets/furi_hal_include/furi_hal_region.h new file mode 100644 index 000000000..10d519ab7 --- /dev/null +++ b/firmware/targets/furi_hal_include/furi_hal_region.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include + +typedef struct { + uint32_t start; + uint32_t end; + int8_t power_limit; + uint8_t duty_cycle; +} FuriHalRegionBand; + +typedef struct { + char country_code[4]; + uint16_t bands_count; + FuriHalRegionBand bands[]; +} FuriHalRegion; + +/** Initialize region */ +void furi_hal_region_init(); + +/** Get Region Data. + * + * Region data may be allocated in Flash or in RAM. + * Keep in mind that we don't do memory management on our side. + * + * @return pointer to FuriHalRegion instance (in RAM or Flash, check before freeing on region update) + */ +const FuriHalRegion* furi_hal_region_get(); + +/** Set device region data + * + * @param region pointer to the FuriHalRegion + */ +void furi_hal_region_set(FuriHalRegion* region); + +/** Check if region data provisioned + * + * @return true if provisioned, false otherwise + */ +bool furi_hal_region_is_provisioned(); + +/** Get region name + * + * 2 letter Region code according to iso 3166 standard + * There are 2 extra values that we use in special cases: + * - "00" - developer edition, unlocked + * - "WW" - world wide, region provisioned by default + * - "--" - no provisioned region + * + * @return Pointer to string + */ +const char* furi_hal_region_get_name(); + +/** Сheck if transmission is allowed on this frequency for your flipper region + * + * @param[in] frequency The frequency + * @param value frequency in Hz + * + * @return true if allowed + */ +bool furi_hal_region_is_frequency_allowed(uint32_t frequency); + +/** Get band data for frequency + * + * + * + * @param[in] frequency The frequency + * + * @return { description_of_the_return_value } + */ +const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency); diff --git a/firmware/targets/furi_hal_include/furi_hal_subghz.h b/firmware/targets/furi_hal_include/furi_hal_subghz.h index b6d132ac3..d610b01b7 100644 --- a/firmware/targets/furi_hal_include/furi_hal_subghz.h +++ b/firmware/targets/furi_hal_include/furi_hal_subghz.h @@ -180,14 +180,6 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value); */ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); -/** Сheck if transmission is allowed on this frequency for your flipper region - * - * @param value frequency in Hz - * - * @return true if allowed - */ -bool furi_hal_subghz_is_tx_allowed(uint32_t value); - /** Set frequency * * @param value frequency in Hz diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index 74a6183ce..78a186931 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -237,7 +237,7 @@ bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { instance->worker_running = true; - if(furi_hal_subghz_is_tx_allowed(frequency)) { + if(furi_hal_region_is_frequency_allowed(frequency)) { instance->frequency = frequency; res = true; } From ba0502ae1bb3d73baa04717da1b160416ee591c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 11 Aug 2022 20:18:02 +0900 Subject: [PATCH 13/26] SubGhz: show region provisioning message (#1580) * SubGhz: region provisioning message * SubGhz: correct region warning text --- .../subghz/scenes/subghz_scene_show_only_rx.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/applications/subghz/scenes/subghz_scene_show_only_rx.c b/applications/subghz/scenes/subghz_scene_show_only_rx.c index 48fa751e0..22e68c978 100644 --- a/applications/subghz/scenes/subghz_scene_show_only_rx.c +++ b/applications/subghz/scenes/subghz_scene_show_only_rx.c @@ -12,13 +12,11 @@ void subghz_scene_show_only_rx_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; popup_set_icon(popup, 67, 12, &I_DolphinFirstStart7_61x51); - popup_set_text( - popup, - "This frequency can\nonly be used for RX\nin your region", - 38, - 40, - AlignCenter, - AlignBottom); + const char* text = "This frequency can\nonly be used for RX\nin your region"; + if(!furi_hal_region_is_provisioned()) { + text = "Update Flipper to unlock frequencies allowed in your region"; + } + popup_set_text(popup, text, 38, 40, AlignCenter, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback); From 79d9731ea52d0a5791e76151e5367d4e0e4417eb Mon Sep 17 00:00:00 2001 From: Vri <109021367+vrifox@users.noreply.github.com> Date: Thu, 11 Aug 2022 13:47:18 +0200 Subject: [PATCH 14/26] fix: typo badusb demo windows (#1579) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: typo badusb demo windows: Fix a typo in the badusb demo script for Windows. * Assets: update manifest Co-authored-by: あく --- assets/resources/Manifest | 4 ++-- assets/resources/badusb/demo_windows.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/resources/Manifest b/assets/resources/Manifest index 7dbd077be..8bfdcef7e 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1659888302 +T:1660218073 D:badusb D:dolphin D:infrared @@ -8,7 +8,7 @@ D:nfc D:subghz D:u2f F:0e41ba26498b7511d7c9e6e6b5e3b149:1592:badusb/demo_macos.txt -F:e538ad2ce5a06ec45e1b5b24824901b1:1552:badusb/demo_windows.txt +F:46a332993ca94b9aa692030ebaa19c70:1552:badusb/demo_windows.txt D:dolphin/L1_Boxing_128x64 D:dolphin/L1_Cry_128x64 D:dolphin/L1_Furippa1_128x64 diff --git a/assets/resources/badusb/demo_windows.txt b/assets/resources/badusb/demo_windows.txt index 013e99e21..df4353510 100644 --- a/assets/resources/badusb/demo_windows.txt +++ b/assets/resources/badusb/demo_windows.txt @@ -13,7 +13,7 @@ STRING Hello World! ENTER DEFAULT_DELAY 50 -REM Copy-Paste previuos string +REM Copy-Paste previous string UP HOME SHIFT DOWN From a39111ade2723e9ccf15866ab9cc8d90c5047546 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 11 Aug 2022 16:20:31 +0400 Subject: [PATCH 15/26] [FL-2723] SubGhz: add protocol Honeywell_WDB / Doorbell (#1560) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add protocol Honeywell_WDB (receive/save/load/transfer) * SubGhz: add parsing data honeywell * SubGhz: fix UI CAME TWEE * SubGhz: add unit_test honeywell_wdb Co-authored-by: あく --- applications/unit_tests/subghz/subghz_test.c | 18 +- assets/unit_tests/subghz/honeywell_wdb.sub | 7 + .../unit_tests/subghz/honeywell_wdb_raw.sub | 22 + assets/unit_tests/subghz/test_random_raw.sub | 7 +- lib/subghz/blocks/math.c | 8 + lib/subghz/blocks/math.h | 8 + lib/subghz/protocols/came_twee.c | 2 +- lib/subghz/protocols/honeywell_wdb.c | 399 ++++++++++++++++++ lib/subghz/protocols/honeywell_wdb.h | 111 +++++ lib/subghz/protocols/registry.c | 21 +- lib/subghz/protocols/registry.h | 1 + 11 files changed, 591 insertions(+), 13 deletions(-) create mode 100644 assets/unit_tests/subghz/honeywell_wdb.sub create mode 100644 assets/unit_tests/subghz/honeywell_wdb_raw.sub create mode 100644 lib/subghz/protocols/honeywell_wdb.c create mode 100644 lib/subghz/protocols/honeywell_wdb.h diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index fb3c7a4eb..f91d27234 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 158 +#define TEST_RANDOM_COUNT_PARSE 188 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -404,6 +404,14 @@ MU_TEST(subghz_decoder_phoenix_v2_test) { "Test decoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); } +MU_TEST(subghz_decoder_honeywell_wdb_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/honeywell_wdb_raw.sub"), + SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME), + "Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -501,6 +509,12 @@ MU_TEST(subghz_encoder_phoenix_v2_test) { "Test encoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n"); } +MU_TEST(subghz_encoder_honeywell_wdb_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/honeywell_wdb.sub")), + "Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -537,6 +551,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_bett_test); MU_RUN_TEST(subghz_decoder_doitrand_test); MU_RUN_TEST(subghz_decoder_phoenix_v2_test); + MU_RUN_TEST(subghz_decoder_honeywell_wdb_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -554,6 +569,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_bett_test); MU_RUN_TEST(subghz_encoder_doitrand_test); MU_RUN_TEST(subghz_encoder_phoenix_v2_test); + MU_RUN_TEST(subghz_encoder_honeywell_wdb_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/honeywell_wdb.sub b/assets/unit_tests/subghz/honeywell_wdb.sub new file mode 100644 index 000000000..bce11cd0d --- /dev/null +++ b/assets/unit_tests/subghz/honeywell_wdb.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 868350000 +Preset: FuriHalSubGhzPreset2FSKDev476Async +Protocol: Honeywell +Bit: 48 +Key: 00 00 0E DB 70 20 00 01 diff --git a/assets/unit_tests/subghz/honeywell_wdb_raw.sub b/assets/unit_tests/subghz/honeywell_wdb_raw.sub new file mode 100644 index 000000000..0fbd6d23e --- /dev/null +++ b/assets/unit_tests/subghz/honeywell_wdb_raw.sub @@ -0,0 +1,22 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 868250000 +Preset: FuriHalSubGhzPreset2FSKDev476Async +Protocol: RAW +RAW_Data: 414 -1374 51 -108 79 -216 189 -584 53 -214 53 -400 215 -264 129 -322 77 -288 79 -54 107 -184 51 -446 53 -160 161 -305 263 -104 264 -134 53 -806 267 -80 187 -314 53 -158 83 -1172 243 -833 79 -188 345 -208 77 -182 225 -100 107 -106 187 -190 105 -432 176 -174 119 -328 79 -432 79 -102 99 -514 127 -218 79 -184 77 -52 101 -356 53 -615 243 -266 181 -102 212 -138 81 -486 205 -574 77 -256 155 -152 217 -78 75 -1010 393 -346 79 -488 107 -284 121 -72 215 -174 183 -54 257 -332 179 -52 79 -238 53 -636 161 -80 227 -950 346 -160 109 -564 295 -160 299 -160 435 -487 312 -52 105 -292 77 -246 137 -498 366 -104 255 -362 97 -210 53 -555 374 -206 129 -96 303 -280 179 -172 75 -102 99 -76 353 -228 131 -252 147 -130 79 -304 103 -82 139 -52 103 -183 77 -284 75 -454 55 -188 77 -222 161 -128 107 -136 187 -270 53 -371 184 -364 103 -284 129 -52 103 -321 81 -554 261 -1048 107 -106 243 -280 103 -478 215 -530 53 -108 53 -236 203 -180 51 -78 77 -338 81 -82 53 -231 75 -124 256 -232 227 -448 131 -340 131 -266 107 -346 51 -254 75 -134 210 -182 103 -280 127 -122 305 -310 255 -528 77 -513 79 -214 209 -102 53 -80 133 -1727 237 -78 79 -242 53 -296 133 -532 53 -513 53 -54 131 -190 53 -661 129 -218 107 -394 103 -554 157 -112 343 -314 103 -283 79 -304 135 -56 111 -272 189 -370 271 -270 105 -956 79 -184 77 -868 307 -156 129 -731 51 -200 161 -84 81 -326 51 -54 157 -168 369 -152 101 -188 81 -398 239 -132 215 -54 105 -182 317 -206 99 -198 97 -274 157 -271 121 -268 200 -330 499 -184 55 -434 133 -646 283 -152 255 -428 101 -350 199 -124 145 -304 308 -102 75 -386 107 -186 129 -534 101 -180 175 -100 151 -98 53 -78 133 -794 183 -150 83 -220 185 -280 83 -537 107 -308 55 -138 79 -714 79 -538 77 -106 133 -242 263 -236 75 -884 215 -136 81 -270 133 -624 105 -132 79 -848 291 -373 79 -244 55 -619 203 -202 77 -156 103 -176 99 -408 107 -318 77 -316 79 -500 55 -691 51 -340 129 -266 53 -486 103 -376 103 -185 51 -156 81 -106 77 -104 79 -502 208 -292 133 -432 105 -52 105 -80 51 -158 317 -372 181 -844 51 -270 107 -312 79 -302 83 -444 53 -640 77 -268 183 -138 85 -192 79 -158 131 -132 155 -220 81 -245 127 -386 185 -296 53 -608 77 -308 51 -822 105 -832 51 -850 155 -242 105 -422 79 -270 155 -76 77 -162 55 -414 +RAW_Data: 109 -630 77 -190 53 -52 131 -860 53 -1300 83 -1122 99 -432 53 -724 81 -390 159 -106 81 -2607 79 -474 75 -694 151 -146 73 -104 53 -380 77 -278 77 -128 73 -148 73 -248 99 -314 75 -154 97 -2225 51 -952 183 -970 77 -1210 51 -326 103 -368 151 -252 121 -784 51 -108 187 -256 227 -242 105 -104 150 -128 77 -1287 173 -2513 77 -1144 105 -1268 111 -3964 101 -1348 81 -2718 81 -302 79 -1999 55 -1268 57 -7269 53 -424 83 -3736 105 -1552 51 -8460 57 -5224 101 -244 121 -4124 103 -10775 133 -1858 73 -20679 51 -5532 97 -1718 103 -3764 51 -6496 79 -792 53 -13269 81 -18787 57 -9140 83 -3302 53 -11039 55 -26162 79 -1713 103 -5860 53 -9589 55 -8389 81 -254 85 -16287 73 -8336 53 -6237 75 -828 55 -19389 73 -8028 79 -6284 83 -3460 77 -13504 75 -3198 75 -1280 51 -1948 51 -758 79 -22076 75 -1681 73 -21693 57 -8106 53 -838 51 -10074 51 -4760 55 -492 79 -6558 79 -22996 75 -13904 53 -5564 55 -16578 83 -25603 77 -410 75 -16694 81 -606 53 -2987 53 -3898 107 -3248 79 -5168 55 -754 81 -20662 53 -11066 51 -8624 79 -26384 79 -2214 81 -7442 79 -12488 53 -1656 71 -4508 55 -15680 57 -6669 51 -5410 71 -6411 53 -6082 79 -13772 53 -5945 55 -574 73 -11921 51 -3472 55 -2323 55 -10414 51 -16069 81 -2678 77 -10775 53 -2106 110 -11794 55 -17082 51 -6184 71 -8376 79 -7152 77 -2691 53 -6332 53 -2074 57 -6804 51 -166 53 -2254 53 -452 51 -6771 53 -42749 53 -6658 73 -2034 111 -3440 109 -626 53 -7291 85 -2546 53 -5287 51 -9902 53 -10040 53 -366 79 -13848 51 -3739 77 -47536 51 -354 77 -228 77 -712 53 -530 53 -162 55 -12640 71 -1708 51 -1034 77 -12891 79 -3334 51 -7644 79 -12676 81 -3036 53 -2038 53 -180 57 -818 55 -21459 71 -3009 51 -6572 53 -4015 105 -642 77 -23618 53 -4921 83 -3026 73 -3672 53 -12654 81 -8632 51 -9419 171 -19195 105 -13041 55 -21910 51 -1051 77 -10292 51 -12884 51 -6589 53 -8718 51 -2510 103 -15406 55 -6014 99 -966 73 -2725 53 -12715 51 -4228 55 -3192 57 -8672 51 -14740 51 -17032 75 -11111 1761 -182 399 -106 215 -270 355 -132 329 -150 177 -312 315 -170 169 -290 331 -162 173 -286 187 -312 163 -300 329 -164 311 -162 171 -316 289 -176 297 -194 311 -164 143 -324 167 -314 163 -310 161 -312 163 -300 175 -300 331 -162 173 -312 161 -312 163 -314 161 -298 189 -300 165 -312 161 -312 189 -276 173 -316 193 -310 163 -312 161 -310 163 -300 175 -296 193 -284 191 -284 187 -310 163 -300 175 -300 169 -320 177 -314 485 -464 177 -292 353 -134 +RAW_Data: 171 -316 311 -154 187 -292 343 -134 337 -136 199 -286 311 -182 157 -294 327 -160 171 -316 161 -312 159 -314 333 -170 311 -164 141 -324 305 -164 299 -176 301 -170 167 -340 133 -338 163 -312 159 -294 189 -298 165 -314 311 -180 155 -294 189 -300 165 -312 187 -284 189 -312 159 -294 189 -296 167 -314 161 -310 189 -312 159 -292 189 -296 167 -312 161 -312 159 -314 193 -268 175 -304 193 -314 163 -312 159 -312 193 -294 495 -458 161 -338 301 -168 165 -304 331 -134 199 -286 309 -184 309 -170 141 -318 331 -162 143 -316 309 -182 157 -294 189 -302 163 -312 309 -184 311 -170 141 -318 331 -162 299 -150 319 -196 139 -314 165 -334 137 -340 159 -312 161 -302 149 -318 331 -162 173 -312 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -300 193 -284 187 -284 189 -312 159 -292 189 -298 167 -312 161 -312 189 -300 173 -294 195 -282 191 -310 485 -472 167 -300 331 -134 171 -312 333 -170 169 -290 331 -162 299 -176 155 -300 333 -162 171 -300 323 -150 145 -340 159 -320 167 -302 319 -150 319 -166 169 -312 331 -162 299 -150 319 -194 139 -314 165 -308 163 -340 133 -338 163 -312 157 -296 327 -160 171 -316 163 -310 161 -312 163 -298 177 -302 193 -314 163 -310 161 -312 163 -300 173 -300 169 -318 177 -290 189 -300 165 -312 161 -312 189 -284 185 -292 189 -300 191 -286 187 -284 191 -312 471 -486 167 -314 313 -152 159 -300 335 -162 169 -308 319 -150 319 -166 169 -312 331 -162 143 -314 311 -180 157 -294 189 -300 165 -314 309 -182 311 -168 141 -318 333 -162 299 -174 295 -194 141 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -160 171 -316 161 -312 159 -314 191 -270 201 -278 193 -314 163 -310 161 -312 163 -300 175 -300 169 -316 177 -292 189 -300 165 -312 161 -312 189 -284 183 -294 189 -298 193 -284 187 -312 163 -312 497 -460 145 -320 325 -168 171 -290 333 -162 171 -314 305 -160 317 -168 169 -290 333 -162 173 -312 283 -182 159 -294 189 -302 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 321 -194 141 -312 167 -334 135 -340 161 -310 163 -312 159 -294 327 -160 171 -316 163 -310 161 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -300 165 -312 161 -310 189 -284 185 -292 189 -300 191 -286 187 -312 161 -300 487 -484 151 -318 335 -138 169 -322 305 -164 171 -314 305 -190 295 -166 171 -290 333 -162 173 -312 283 -182 159 -296 191 -300 +RAW_Data: 165 -312 333 -160 311 -170 141 -318 331 -164 299 -148 321 -194 139 -316 165 -336 135 -340 133 -338 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -298 193 -310 163 -312 159 -312 163 -300 175 -296 193 -312 163 -312 159 -312 163 -300 175 -298 167 -320 175 -290 191 -296 193 -286 187 -310 163 -300 175 -296 501 -458 187 -288 347 -154 151 -316 325 -162 171 -316 313 -152 301 -194 141 -316 331 -162 143 -314 311 -182 155 -294 189 -302 163 -314 309 -182 311 -168 143 -318 331 -162 301 -174 295 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -158 173 -314 163 -312 159 -306 173 -314 165 -306 191 -284 189 -284 189 -312 157 -294 191 -300 163 -314 187 -284 189 -284 187 -292 189 -296 165 -314 161 -312 189 -284 185 -294 189 -298 193 -286 485 -492 167 -298 323 -150 175 -302 331 -164 171 -300 321 -150 317 -166 167 -308 331 -134 171 -316 309 -182 129 -318 189 -302 163 -314 309 -182 311 -170 141 -318 331 -162 301 -148 321 -194 139 -314 167 -334 137 -338 161 -310 163 -312 159 -294 327 -160 171 -316 161 -312 159 -312 193 -270 175 -304 193 -314 163 -312 159 -312 161 -314 161 -296 189 -304 165 -312 187 -284 189 -276 173 -318 195 -278 193 -284 187 -312 163 -300 175 -298 169 -318 511 -460 147 -318 327 -168 169 -292 331 -164 171 -314 305 -160 315 -168 171 -290 333 -162 171 -314 283 -182 159 -294 189 -300 165 -314 307 -184 311 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 157 -294 327 -160 171 -316 163 -310 161 -304 175 -314 167 -304 191 -286 187 -284 189 -284 187 -292 189 -300 165 -312 189 -284 187 -286 185 -294 189 -296 165 -314 161 -312 187 -286 185 -294 189 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -168 171 -292 331 -164 299 -174 151 -316 325 -162 171 -316 289 -176 151 -316 187 -296 167 -312 311 -180 307 -170 141 -318 331 -162 299 -150 319 -196 139 -314 165 -334 137 -340 159 -312 161 -302 149 -320 329 -164 171 -314 159 -312 163 -300 175 -298 193 -310 163 -312 161 -310 163 -312 161 -296 189 -302 191 -286 187 -284 189 -312 159 -292 189 -296 167 -314 161 -310 189 -284 187 -292 189 -300 193 -284 485 -494 167 -296 323 -150 175 -312 313 -170 169 -292 333 -162 299 -176 151 -314 327 -160 171 -316 291 -176 149 -316 189 -296 165 -314 309 -182 307 -168 141 -318 331 -164 299 -148 321 -194 141 -314 165 -334 137 -338 161 -312 +RAW_Data: 161 -302 147 -320 331 -162 171 -314 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -296 195 -284 189 -284 189 -312 159 -296 513 -468 159 -300 333 -162 171 -300 323 -150 171 -314 325 -162 311 -164 171 -314 305 -160 159 -296 327 -160 171 -316 161 -312 161 -312 335 -170 311 -164 141 -324 321 -154 299 -194 309 -164 143 -326 167 -314 161 -312 159 -312 163 -302 173 -300 331 -162 173 -312 161 -312 163 -300 175 -300 167 -320 153 -312 191 -296 167 -312 161 -312 189 -312 159 -292 189 -298 167 -312 161 -312 159 -314 193 -268 177 -302 193 -316 161 -312 159 -312 193 -294 497 -456 187 -312 303 -166 165 -306 331 -132 201 -286 309 -182 313 -168 143 -318 331 -162 143 -314 311 -182 157 -294 189 -302 165 -312 309 -182 311 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -338 161 -312 161 -300 149 -320 331 -162 171 -314 161 -310 163 -302 173 -298 193 -310 165 -310 161 -310 163 -312 161 -296 189 -300 193 -286 187 -284 189 -312 157 -294 189 -298 165 -314 161 -310 189 -284 187 -292 189 -300 193 -284 485 -494 167 -298 321 -150 171 -318 323 -162 171 -314 289 -176 297 -194 141 -314 331 -162 143 -316 309 -182 155 -294 189 -302 163 -314 309 -182 311 -168 143 -318 331 -162 301 -148 321 -194 139 -314 167 -334 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -300 175 -296 193 -312 163 -312 159 -312 163 -300 175 -298 167 -320 175 -290 191 -296 193 -286 187 -310 163 -312 161 -296 513 -468 159 -300 333 -162 171 -302 321 -150 175 -300 333 -162 311 -162 171 -316 289 -176 153 -314 327 -160 171 -316 163 -312 159 -312 307 -168 335 -138 169 -320 307 -164 297 -176 301 -194 141 -318 165 -336 137 -338 133 -338 163 -312 159 -294 327 -160 171 -316 161 -312 161 -312 163 -298 177 -302 169 -318 177 -292 189 -298 167 -312 189 -284 189 -312 157 -294 189 -298 167 -312 161 -312 159 -312 193 -270 203 -302 169 -314 161 -312 189 -310 467 -484 145 -318 327 -168 143 -316 331 -162 173 -312 307 -160 313 -170 141 -318 331 -164 143 -342 281 -184 157 -294 189 -302 165 -312 307 -184 313 -168 141 -320 331 -162 299 -150 319 -194 141 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -158 173 -314 163 -310 161 -312 165 -298 175 -304 193 -312 163 -312 159 -312 +RAW_Data: 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 185 -292 189 -298 193 -284 189 -310 163 -312 497 -460 145 -320 325 -170 169 -290 333 -162 171 -314 307 -158 317 -168 169 -290 333 -162 171 -314 281 -182 159 -296 189 -300 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -160 173 -314 163 -312 159 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 175 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 193 -284 187 -312 161 -314 471 -486 167 -314 313 -152 159 -300 335 -162 169 -308 321 -156 329 -170 127 -318 321 -176 155 -300 333 -164 169 -302 165 -314 161 -310 329 -168 299 -166 151 -328 311 -154 331 -168 299 -178 143 -318 153 -322 167 -332 149 -320 151 -318 165 -304 321 -156 181 -290 189 -300 173 -294 177 -294 189 -302 173 -294 177 -294 189 -302 173 -294 177 -318 193 -278 173 -294 179 -292 191 -302 173 -294 177 -294 189 -302 173 -320 177 -294 195 -278 175 -318 491 -460 163 -314 333 -158 159 -294 327 -160 171 -316 311 -180 307 -170 141 -318 331 -162 143 -316 309 -182 157 -294 189 -302 165 -312 309 -182 313 -168 141 -318 331 -164 299 -148 321 -194 141 -314 165 -334 137 -338 135 -338 161 -312 159 -294 329 -158 173 -314 163 -310 161 -306 173 -314 165 -304 193 -284 187 -286 189 -276 197 -294 193 -310 163 -312 161 -310 163 -300 175 -296 193 -310 165 -284 187 -310 163 -300 175 -300 169 -318 177 -316 483 -466 187 -292 341 -134 171 -308 319 -150 179 -300 333 -164 309 -162 171 -316 313 -152 153 -316 327 -160 171 -316 163 -310 161 -312 307 -166 337 -136 171 -322 305 -164 299 -174 301 -194 141 -318 165 -336 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -302 165 -312 189 -284 189 -284 185 -294 189 -296 165 -314 161 -310 189 -284 187 -294 189 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -168 171 -290 333 -162 299 -176 151 -316 325 -162 171 -316 289 -176 151 -314 189 -296 165 -314 309 -182 305 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -340 133 -338 161 -302 149 -320 329 -164 171 -286 187 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -312 159 -296 189 -302 191 -286 187 -284 189 -312 159 -292 191 -296 165 -314 161 -310 189 -284 187 -292 +RAW_Data: 189 -300 193 -284 485 -494 167 -298 321 -150 177 -300 327 -150 167 -328 305 -160 319 -168 171 -290 333 -162 171 -314 281 -184 159 -296 189 -300 165 -314 307 -184 311 -170 141 -318 333 -162 299 -150 319 -194 139 -314 167 -334 135 -340 133 -338 163 -312 159 -294 327 -158 173 -314 163 -312 159 -312 165 -298 177 -302 193 -314 163 -310 161 -312 163 -300 173 -300 167 -318 177 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 191 -286 187 -284 189 -300 487 -484 149 -320 333 -138 171 -322 321 -154 151 -316 327 -160 311 -164 173 -312 307 -160 161 -298 355 -132 173 -314 163 -310 161 -312 335 -170 311 -164 143 -322 307 -164 323 -150 301 -196 141 -318 165 -334 137 -338 161 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 173 -298 195 -310 163 -312 159 -312 163 -312 159 -296 189 -300 193 -284 189 -284 189 -284 185 -294 189 -296 165 -314 161 -312 189 -284 185 -294 189 -298 193 -286 485 -468 193 -296 323 -150 147 -340 313 -168 171 -292 331 -164 299 -174 151 -316 325 -160 173 -316 289 -176 149 -316 189 -294 165 -314 309 -182 307 -170 141 -318 331 -164 299 -148 321 -194 139 -314 167 -306 165 -338 133 -338 163 -312 159 -294 327 -160 173 -314 163 -312 161 -310 165 -300 175 -300 169 -318 177 -290 189 -298 165 -314 187 -284 189 -312 159 -294 189 -298 165 -314 161 -310 161 -306 173 -316 193 -280 191 -312 159 -312 163 -300 515 -460 161 -312 305 -190 135 -328 329 -134 201 -286 309 -182 311 -168 143 -318 331 -162 143 -316 309 -182 157 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -334 137 -340 159 -312 163 -300 149 -318 331 -162 173 -312 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -312 161 -298 189 -300 165 -312 161 -312 189 -312 159 -292 191 -300 191 -286 485 -468 193 -298 323 -148 147 -342 323 -160 173 -314 289 -176 297 -196 139 -314 331 -162 143 -314 311 -180 157 -292 191 -300 165 -312 311 -182 309 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -338 161 -312 161 -312 159 -294 329 -158 173 -314 163 -310 161 -312 165 -298 175 -304 193 -312 163 -310 161 -310 163 -302 173 -300 169 -318 175 -292 189 -300 165 -312 161 -310 189 -278 173 -316 195 -280 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -328 329 -134 199 -288 309 -182 311 -168 143 -318 +RAW_Data: 331 -162 143 -316 309 -182 157 -292 191 -300 165 -312 309 -182 313 -168 141 -318 331 -164 299 -174 295 -194 141 -314 165 -334 137 -340 133 -338 163 -312 159 -292 327 -160 171 -316 163 -310 161 -312 165 -298 175 -304 193 -312 163 -312 159 -312 163 -300 175 -300 169 -316 177 -292 189 -298 167 -312 161 -310 189 -278 173 -316 193 -282 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -326 331 -132 201 -286 309 -184 309 -170 141 -318 333 -162 143 -314 311 -180 159 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 135 -340 159 -312 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 175 -294 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 153 -314 191 -296 193 -286 187 -284 189 -312 161 -294 509 -468 159 -298 335 -162 169 -304 323 -150 175 -300 335 -162 311 -160 173 -316 313 -152 151 -316 327 -160 171 -316 163 -312 159 -312 307 -168 335 -138 169 -322 305 -164 299 -176 299 -194 141 -316 167 -334 137 -340 159 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 175 -296 193 -310 165 -310 161 -312 161 -302 173 -296 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 177 -290 189 -296 193 -286 187 -310 163 -300 175 -296 501 -484 161 -288 347 -154 151 -316 325 -160 173 -314 313 -152 301 -196 141 -314 331 -162 143 -316 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 163 -298 177 -302 193 -314 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 193 -292 179 -308 167 -314 161 -312 189 -302 481 -460 173 -320 303 -168 169 -294 331 -164 171 -314 307 -160 319 -168 169 -292 331 -162 143 -342 283 -182 159 -294 189 -302 165 -312 309 -184 311 -168 143 -318 331 -162 299 -150 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 165 -298 177 -302 193 -312 163 -312 161 -310 163 -314 161 -296 189 -302 165 -312 187 -284 189 -284 185 -294 189 -296 165 -314 187 -284 189 -302 173 -294 195 -310 491 -458 163 -318 319 -156 153 -314 327 -160 171 -316 311 -152 327 -170 141 -316 331 -164 143 -314 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -316 333 -162 299 -150 +RAW_Data: 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -160 171 -316 161 -312 159 -314 163 -300 175 -302 193 -314 163 -310 161 -310 163 -300 175 -300 167 -318 177 -290 191 -300 165 -312 161 -312 187 -284 185 -292 189 -300 191 -286 187 -310 163 -300 487 -484 149 -320 335 -138 169 -322 305 -164 171 -314 305 -190 293 -168 169 -292 333 -162 171 -314 281 -184 159 -296 189 -300 165 -312 309 -184 311 -170 141 -318 331 -162 299 -150 319 -196 139 -314 165 -336 137 -338 133 -338 163 -312 159 -294 327 -160 171 -316 161 -312 159 -312 165 -298 177 -302 193 -314 163 -310 161 -310 163 -314 161 -296 189 -302 165 -312 187 -286 189 -276 173 -318 193 -280 191 -284 189 -310 163 -300 175 -300 167 -318 513 -460 167 -314 311 -152 161 -324 311 -162 169 -310 329 -160 293 -190 137 -330 329 -132 173 -316 311 -180 129 -318 189 -300 165 -312 309 -182 311 -168 141 -320 329 -164 299 -174 295 -194 141 -314 167 -334 137 -340 133 -338 161 -312 159 -294 329 -158 173 -314 163 -310 161 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 189 -300 165 -312 161 -312 189 -284 183 -292 189 -300 193 -284 187 -284 189 -314 471 -486 145 -318 327 -168 171 -290 331 -162 173 -312 307 -158 317 -168 169 -290 333 -162 143 -342 283 -182 159 -294 189 -300 165 -312 309 -182 313 -168 143 -318 331 -162 299 -176 293 -196 139 -314 167 -334 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -302 193 -284 187 -284 189 -302 149 -318 193 -280 191 -284 189 -284 189 -300 173 -300 169 -316 177 -316 483 -476 153 -320 329 -134 201 -286 309 -182 157 -294 355 -132 339 -136 169 -320 315 -162 171 -302 323 -148 171 -318 159 -318 147 -318 327 -168 313 -164 169 -302 321 -150 317 -166 305 -164 169 -324 169 -314 163 -310 161 -310 163 -300 175 -296 331 -164 171 -314 161 -312 163 -300 175 -298 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 189 -298 195 -284 187 -284 189 -314 159 -294 513 -470 159 -300 333 -162 171 -300 323 -150 169 -316 325 -160 311 -164 173 -312 307 -158 161 -294 329 -158 173 -314 163 -312 159 -312 335 -170 311 -164 141 -324 305 -164 323 -152 301 -194 141 -318 165 -336 137 -338 161 -312 161 -312 159 -294 329 -158 173 -314 163 -310 161 -312 +RAW_Data: 165 -298 175 -304 169 -318 175 -290 191 -298 165 -314 187 -284 189 -312 159 -294 191 -296 167 -312 161 -312 159 -314 193 -270 201 -304 167 -314 163 -312 159 -312 493 -486 145 -318 325 -170 141 -316 331 -162 173 -314 305 -160 313 -170 141 -318 331 -162 143 -342 283 -182 159 -294 189 -302 165 -312 309 -182 313 -168 141 -318 331 -162 301 -148 321 -194 141 -314 165 -334 137 -340 159 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 175 -296 193 -310 165 -310 161 -310 163 -302 173 -296 193 -312 161 -312 159 -312 163 -300 175 -300 167 -320 177 -290 189 -298 193 -286 187 -284 189 -312 161 -294 513 -468 159 -300 333 -162 171 -302 321 -150 171 -316 323 -162 311 -164 171 -314 307 -158 159 -296 327 -160 171 -316 163 -310 161 -306 321 -168 339 -134 171 -306 321 -150 317 -166 337 -164 143 -324 167 -314 163 -312 159 -312 163 -300 175 -298 331 -162 173 -312 161 -312 163 -300 175 -300 193 -310 163 -312 161 -310 163 -312 161 -296 189 -300 193 -284 189 -284 189 -284 185 -294 189 -296 165 -314 161 -312 187 -286 185 -292 191 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -146 167 -344 305 -158 315 -168 143 -318 331 -162 143 -342 283 -182 159 -294 189 -302 163 -314 307 -184 311 -168 141 -318 333 -162 299 -174 295 -194 141 -314 167 -334 137 -338 161 -312 161 -312 159 -294 329 -160 171 -316 163 -310 161 -312 163 -300 175 -302 169 -318 175 -290 191 -298 165 -312 189 -284 189 -312 159 -292 189 -298 165 -314 161 -312 189 -282 195 -268 203 -304 169 -312 163 -312 187 -278 507 -460 173 -320 303 -166 171 -294 331 -164 171 -314 305 -160 319 -168 169 -292 331 -164 171 -314 281 -182 159 -294 191 -300 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -160 171 -316 161 -312 159 -314 163 -300 175 -302 193 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -292 189 -300 165 -312 161 -310 189 -284 193 -292 179 -308 167 -314 161 -312 189 -302 483 -458 173 -320 303 -168 169 -294 331 -164 171 -314 307 -158 319 -168 169 -292 331 -164 171 -314 283 -182 159 -294 191 -300 165 -312 309 -182 313 -168 143 -316 331 -164 299 -150 319 -194 141 -314 165 -334 137 -340 133 -338 161 -312 159 -294 327 -160 171 -316 161 -312 159 -314 163 -298 177 -304 193 -312 163 -312 161 -310 163 -314 161 -296 189 -302 163 -314 161 -310 189 -284 +RAW_Data: 185 -294 189 -296 165 -314 189 -284 189 -312 157 -294 189 -300 497 -456 189 -284 345 -154 153 -316 325 -160 173 -314 315 -150 325 -170 141 -314 331 -164 143 -314 309 -182 157 -294 189 -302 163 -314 307 -184 311 -168 141 -318 333 -162 299 -174 295 -194 141 -314 165 -334 137 -340 159 -312 163 -300 149 -318 331 -164 171 -314 159 -312 163 -300 175 -298 193 -310 163 -312 159 -312 163 -312 159 -296 189 -300 165 -314 187 -284 189 -312 157 -294 189 -298 165 -314 161 -310 189 -284 187 -292 189 -300 193 -284 485 -468 193 -296 323 -150 175 -312 313 -168 171 -292 331 -164 299 -176 149 -316 325 -162 171 -316 289 -176 151 -314 189 -296 165 -314 309 -182 307 -168 143 -316 331 -164 299 -150 319 -194 141 -312 167 -334 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -300 173 -296 169 -318 177 -292 189 -300 165 -312 161 -312 189 -284 183 -294 189 -294 195 -284 187 -284 191 -300 173 -296 499 -482 163 -314 321 -154 153 -316 325 -160 173 -314 313 -152 301 -196 139 -316 331 -162 143 -314 311 -182 155 -294 189 -302 163 -314 309 -182 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 135 -340 159 -312 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -296 193 -310 165 -310 161 -312 161 -302 173 -296 169 -316 177 -292 189 -300 165 -314 161 -310 189 -284 185 -292 189 -296 193 -286 187 -284 189 -300 175 -294 499 -482 163 -314 321 -154 153 -316 325 -160 171 -316 313 -152 325 -170 141 -314 331 -164 143 -314 311 -180 157 -294 191 -300 165 -312 309 -182 311 -168 141 -320 329 -164 299 -174 295 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -160 173 -314 163 -312 159 -312 163 -300 175 -302 195 -310 163 -312 159 -312 163 -300 175 -298 169 -318 177 -292 189 -298 165 -314 161 -310 189 -284 185 -292 189 -298 193 -284 187 -286 189 -312 471 -486 145 -320 325 -168 171 -290 331 -162 173 -312 307 -160 315 -168 169 -292 331 -162 143 -342 283 -182 159 -294 189 -302 165 -312 309 -182 311 -170 141 -318 331 -164 299 -148 319 -196 139 -314 167 -334 135 -340 161 -310 163 -300 149 -320 331 -162 171 -314 161 -310 163 -314 161 -296 189 -296 165 -314 161 -310 189 -284 185 -292 189 -298 165 -312 161 -312 189 -276 173 -318 193 -278 191 -286 187 -284 189 -300 175 -298 169 -318 177 -314 483 -466 187 -294 339 -136 169 -306 +RAW_Data: 321 -150 177 -300 333 -164 311 -160 173 -314 313 -152 155 -314 327 -160 171 -316 163 -312 159 -312 307 -166 337 -138 169 -322 305 -164 299 -176 301 -194 141 -316 165 -336 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -300 175 -294 169 -318 177 -292 189 -300 165 -312 161 -312 189 -284 183 -292 189 -296 193 -286 187 -284 189 -302 173 -296 499 -458 187 -312 321 -154 153 -316 325 -162 171 -316 313 -152 301 -194 141 -314 331 -162 143 -316 309 -182 157 -292 189 -302 163 -314 309 -182 311 -170 141 -318 331 -162 311 -160 295 -190 163 -302 165 -304 165 -312 161 -338 163 -312 157 -294 327 -160 171 -316 161 -312 159 -312 165 -298 177 -302 193 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 159 -312 189 -284 185 -290 189 -300 193 -284 189 -284 189 -312 471 -460 483 -2128 125 -52 75 -102 75 -154 101 -100 147 -272 149 -328 75 -228 511 -441 77 -212 87 -114 189 -54 263 -156 171 -393 127 -102 183 -110 293 -242 395 -320 107 -52 81 -346 53 -572 155 -381 305 -234 101 -126 228 -156 195 -102 281 -126 518 -52 313 -240 187 -54 79 -316 133 -136 213 -108 79 -80 185 -464 181 -76 379 -80 81 -506 233 -318 103 -78 53 -559 51 -240 53 -106 207 -136 163 -136 81 -218 187 -104 349 -266 51 -266 129 -80 107 -450 131 -331 127 -359 641 -108 472 -100 547 -82 79 -246 107 -560 567 -130 403 -389 149 -179 77 -526 235 -108 81 -78 51 -455 75 -106 105 -240 101 -557 183 -184 255 -102 311 -130 147 -174 457 -354 75 -442 81 -344 331 -76 51 -106 133 -54 161 -560 77 -130 77 -294 257 -52 99 -126 73 -565 51 -242 131 -497 55 -354 347 -404 81 -108 540 -286 185 -465 219 -264 296 -106 77 -294 193 -110 567 -52 287 -134 53 -106 55 -330 263 -210 83 -86 109 -134 349 -80 221 -80 207 -260 279 -76 75 -74 75 -76 99 -130 443 -78 77 -338 129 -226 179 -280 129 -228 75 -617 185 -324 423 -160 259 -673 159 -188 362 -212 205 -383 151 -316 235 -240 183 -188 79 -56 107 -80 53 -154 417 -158 211 -238 109 -80 79 -218 215 -108 105 -354 215 -112 191 -56 103 -132 77 -236 605 -152 51 -78 185 -78 127 -126 551 -156 135 -186 127 -724 131 -56 81 -378 345 -182 109 -316 107 -316 337 -128 151 -294 101 -1002 101 -52 335 -256 51 -330 81 -448 153 -158 127 -272 131 -160 105 -220 767 -132 +RAW_Data: 75 -210 131 -78 181 -243 345 -108 107 -80 105 -160 107 -218 127 -82 537 -266 239 -340 181 -76 105 -78 421 -482 53 -132 321 -134 51 -262 77 -480 103 -271 475 -154 159 -80 313 -132 79 -282 235 -126 75 -202 175 -226 151 -198 901 -210 51 -78 235 -348 79 -130 103 -584 107 -456 105 -54 431 -54 79 -106 133 -242 105 -486 155 -104 129 -228 147 -100 77 -618 357 -154 531 -104 51 -160 105 -136 109 -140 269 -366 51 -832 53 -270 135 -108 51 -186 51 -160 535 -130 77 -296 51 -182 131 -106 341 -56 135 -194 530 -294 181 -562 75 -179 127 -364 207 -74 125 -332 149 -76 129 -102 103 -102 51 -128 173 -122 482 -474 229 -200 97 -790 105 -104 79 -104 341 -262 101 -110 111 -82 109 -433 271 -210 51 -346 245 -54 209 -284 157 -106 293 -234 77 -826 157 -52 127 -228 299 -490 159 -140 137 -164 247 -294 135 -52 131 -266 77 -128 385 -158 81 -276 356 -476 53 -170 55 -463 79 -190 53 -808 51 -80 159 -106 161 -162 83 -225 187 -341 101 -520 159 -54 428 -182 341 -108 79 -274 77 -108 431 -392 77 -132 131 -138 83 -58 135 -274 305 -300 83 -398 79 -534 131 -528 263 -52 261 -264 437 -342 77 -102 389 -332 103 -130 131 -322 105 -106 53 -134 183 -188 79 -82 81 -104 53 -316 269 -56 347 -286 341 -270 161 -52 131 -136 223 -110 341 -318 469 -138 143 -110 83 -80 53 -54 183 -346 385 -906 51 -382 75 -154 51 -52 207 -186 53 -78 51 -106 293 -52 155 -126 306 -130 412 -416 187 -82 339 -160 135 -194 163 -136 81 -78 281 -426 229 -76 227 -532 177 -528 51 -244 269 -616 75 -52 418 -136 53 -82 51 -154 97 -126 233 -52 51 -740 77 -162 81 -304 263 -162 217 -448 275 -164 185 -138 139 -54 277 -348 531 -642 376 -274 267 -182 75 -126 103 -615 103 -236 81 -380 77 -52 241 -80 105 -438 111 -192 181 -54 135 -186 113 -58 243 -140 57 -385 189 -158 133 -675 231 -80 241 -236 131 -106 109 -108 55 -136 555 -132 303 -494 341 -316 135 -112 302 -366 97 -98 101 -310 177 -78 427 -297 151 -579 163 -314 129 -78 51 -233 105 -210 103 -202 217 -180 121 -229 125 -302 221 -52 235 -158 187 -110 135 -162 51 -108 105 -398 221 -82 297 -110 53 -1400 213 -106 51 -454 723 -368 79 -104 79 -134 81 -323 51 -372 79 -80 235 -132 549 -164 81 -104 129 -602 371 -160 129 -536 179 -234 133 -210 236 -489 159 -52 237 -210 129 -264 53 -242 105 -106 53 -114 +RAW_Data: 193 -290 191 -436 343 -311 207 -322 53 -400 51 -882 135 -678 375 -244 317 -192 380 -558 260 -154 710 -80 237 -218 109 -250 81 -372 107 -160 646 -286 125 -178 269 -726 51 -106 79 -298 523 -682 159 -498 265 -465 127 -592 177 -100 149 -687 103 -78 357 -102 53 -158 105 -240 79 -618 105 -130 79 -478 77 -154 450 -186 53 -192 137 -1038 105 -160 266 -136 51 -345 53 -80 157 -108 235 -102 483 -54 109 -234 327 -376 51 -462 366 -289 163 -108 75 -262 261 -134 81 -78 105 -136 81 -378 105 -272 139 -106 209 -80 205 -184 101 -76 101 -180 229 -427 99 -430 125 -100 103 -469 125 -102 221 -130 209 -106 105 -104 201 -274 332 -232 105 -166 161 -104 275 -80 131 -1000 321 -156 189 -166 81 -130 367 -262 153 -258 75 -260 127 -542 127 -464 107 -80 107 -108 303 -240 77 -238 181 -282 77 -76 224 -104 75 -74 225 -554 131 -56 55 -164 51 -318 247 -130 159 -158 77 -76 285 -354 133 -52 135 -420 155 -256 129 -78 265 -831 103 -231 107 -674 285 -653 337 -102 257 -182 101 -146 147 -303 75 -206 365 -268 157 -54 81 -504 133 -472 107 -82 161 -80 133 -461 81 -825 79 -798 101 -206 207 -80 185 -980 209 -56 247 -246 51 -106 131 -78 79 -236 53 -106 51 -98 101 -206 127 -78 151 -98 279 -155 157 -468 131 -72 173 -372 329 -212 79 -52 101 -375 77 -286 51 -188 185 -308 191 -56 555 -320 179 -86 193 -490 105 -214 81 -138 53 -216 211 -112 57 -134 213 -212 131 -714 73 -128 155 -590 51 -452 189 -261 247 -162 105 -404 167 -56 77 -354 81 -56 215 -316 129 -372 366 -288 133 -56 295 -294 51 -822 53 -482 295 -340 321 -188 459 -631 147 -212 201 -100 173 -258 305 -261 51 -208 97 -124 103 -598 159 -206 77 -710 213 -190 241 -158 133 -186 385 -266 219 -350 133 -52 157 -78 51 -156 403 -162 189 -300 259 -202 103 -760 179 -258 173 -82 431 -164 161 -373 133 -208 191 -82 237 -52 135 -384 131 -192 55 -52 285 -52 79 -274 57 -140 109 -306 53 -132 133 -240 53 -104 51 -214 79 -158 123 -98 99 -126 77 -178 173 -334 178 -518 129 -236 337 -206 230 -100 225 -52 152 -102 103 -308 51 -52 203 -114 139 -318 211 -396 183 -78 51 -106 77 -164 83 -380 133 -234 237 -54 79 -158 83 -84 137 -136 323 -158 365 -128 157 -108 81 -194 109 -618 155 -363 191 -190 109 -110 55 -80 163 -224 79 -82 105 -270 133 -314 159 -106 153 -356 77 -76 75 -458 149 -74 +RAW_Data: 101 -128 53 -130 153 -212 447 -230 171 -636 75 -98 324 -362 51 -160 217 -218 51 -310 101 -152 379 -280 151 -176 203 -210 51 -130 336 -232 179 -596 629 -298 55 -1302 261 -108 109 -80 77 -162 237 -52 125 -52 75 -100 125 -148 297 -426 107 -110 133 -238 155 -228 123 -100 247 -74 179 -126 99 -148 99 -134 81 -194 81 -248 53 -164 135 -82 109 -717 53 -220 81 -234 79 -344 53 -474 79 -154 51 -618 109 -142 83 -593 135 -134 105 -136 81 -243 413 -228 121 -174 125 -328 53 -658 361 -74 401 -280 131 -132 85 -56 139 -298 157 -481 51 -52 129 -76 75 -152 127 -507 321 -486 185 -264 103 -54 325 -76 183 -104 53 -246 81 -78 185 -210 155 -112 55 -80 77 -720 103 -54 51 -450 51 -104 107 -246 185 -78 267 -482 221 -580 113 -222 365 -80 135 -138 199 -296 261 -164 107 -80 131 -134 107 -272 323 -1120 51 -476 81 -106 211 -132 107 -352 183 -134 133 -108 215 -220 55 -666 131 -218 79 -82 253 -56 103 -52 235 -106 103 -134 185 -532 111 -188 361 -399 183 -693 238 -104 567 -106 113 -280 107 -52 287 -106 161 -908 103 -376 339 -180 73 -200 101 -330 209 -54 107 -220 315 -132 216 -138 159 -438 135 -190 73 -130 510 -244 53 -294 81 -84 171 -138 53 -460 515 -82 219 -315 291 -54 107 -270 107 -54 53 -160 79 -374 209 -154 97 -74 233 -454 125 -144 119 -96 99 -542 75 -1200 103 -204 99 -172 95 -98 127 -78 75 -102 103 -320 241 -820 77 -78 105 -326 135 -264 53 -216 133 -517 211 -228 103 -52 257 -455 127 -74 77 -78 235 -436 151 -102 75 -152 75 -76 75 -303 51 -254 177 -284 103 -152 207 -156 79 -302 53 -610 79 -214 133 -80 243 -110 107 -108 185 -286 155 -212 187 -384 75 -128 77 -80 129 -130 99 -76 156 -104 185 -82 81 -242 217 -380 81 -294 157 -182 161 -134 131 -104 77 -52 181 -150 75 -98 147 -230 129 -760 161 -273 137 -84 111 -674 53 -80 127 -317 265 -210 79 -242 297 -238 75 -328 105 -244 345 -342 131 -254 151 -378 103 -335 101 -288 75 -154 275 -498 75 -224 372 -80 157 -190 395 -268 81 -52 105 -160 277 -510 107 -262 105 -192 109 -188 81 -586 105 -78 123 -98 201 -182 55 -614 101 -170 175 -285 79 -222 191 -658 161 -194 135 -532 107 -810 77 -134 241 -128 147 -150 276 -200 97 -230 157 -104 171 -282 77 -212 77 -80 406 -714 259 -182 131 -128 161 -112 81 -380 79 -290 135 -777 345 -370 385 -178 51 -364 +RAW_Data: 215 -189 53 -108 83 -320 209 -530 51 -265 51 -54 109 -242 351 -362 51 -102 51 -156 173 -247 255 -100 99 -176 99 -52 224 -262 53 -80 279 -356 51 -76 379 -176 75 -220 77 -52 129 -208 129 -304 101 -378 157 -52 53 -102 179 -228 255 -311 131 -192 235 -52 51 -126 273 -721 53 -294 161 -170 55 -376 81 -268 131 -98 129 -268 81 -158 107 -80 161 -214 129 -110 501 -220 185 -688 79 -132 325 -212 53 -295 105 -104 51 -106 79 -372 153 -106 137 -84 193 -741 51 -561 51 -402 390 -126 149 -250 327 -338 177 -202 177 -931 105 -271 423 -768 53 -430 159 -110 217 -104 161 -460 249 -82 79 -186 79 -104 53 -132 79 -218 55 -298 53 -214 81 -354 51 -108 107 -196 273 -80 79 -104 153 -100 175 -76 131 -220 81 -56 131 -368 217 -116 137 -82 169 -342 209 -106 319 -396 75 -104 253 -130 149 -430 127 -130 81 -196 55 -404 105 -726 181 -224 199 -106 79 -220 159 -180 75 -126 201 -128 75 -833 127 -128 125 -230 249 -184 51 -218 79 -240 163 -222 135 -82 103 -80 159 -765 107 -276 237 -438 207 -162 133 -128 135 -316 105 -312 137 -486 181 -158 77 -769 183 -764 533 -186 77 -100 173 -128 202 -174 174 -102 185 -52 51 -128 177 -358 101 -96 145 -126 75 -184 135 -558 51 -186 211 -241 237 -154 203 -508 103 -562 171 -320 99 -148 127 -212 53 -472 77 -128 147 -100 105 -136 111 -322 206 -238 79 -162 51 -559 109 -198 113 -461 53 -849 159 -230 51 -306 121 -316 105 -78 105 -182 153 -234 131 -226 83 -800 105 -104 215 -52 185 -572 235 -660 97 -922 53 -517 53 -80 133 -302 53 -134 345 -78 111 -374 133 -80 157 -106 185 -184 373 -110 55 -292 129 -140 247 -240 347 -130 73 -227 75 -648 153 -128 75 -1002 155 -335 169 -404 101 -76 175 -126 103 -373 79 -402 217 -218 101 -171 301 -158 204 -76 123 -100 51 -148 251 -334 77 -211 103 -304 359 -78 105 -52 99 -560 101 -288 303 -436 131 -234 179 -252 131 -656 51 -260 129 -160 79 -106 51 -184 203 -152 103 -234 155 -200 235 -52 133 -164 324 -106 107 -82 107 -348 313 -188 79 -372 79 -549 185 -82 79 -246 265 -720 107 -788 77 -585 79 -128 75 -130 203 -76 75 -206 228 -234 79 -180 101 -532 210 -282 229 -412 103 -140 55 -54 77 -316 151 -356 51 -102 75 -272 51 -506 51 -744 329 -340 129 -104 135 -300 167 -1318 107 -186 51 -136 107 -603 107 -338 105 -492 131 -250 107 -80 109 -170 79 -162 +RAW_Data: 101 -102 109 -306 181 -330 209 -76 101 -286 79 -126 51 -156 103 -78 357 -248 77 -260 51 -76 99 -320 323 -76 99 -124 199 -632 105 -220 290 -260 125 -234 75 -272 103 -252 423 -623 81 -80 105 -264 77 -1040 51 -106 107 -1561 81 -732 107 -82 167 -327 159 -626 53 -162 53 -162 107 -238 235 -106 163 -108 105 -104 105 -136 133 -306 51 -430 129 -152 109 -86 111 -56 81 -616 161 -130 51 -514 107 -236 208 -110 193 -638 133 -82 109 -543 216 -457 111 -84 169 -1168 201 -52 75 -78 289 -284 103 -874 105 -166 81 -244 129 -54 214 -398 81 -56 137 -410 81 -268 159 -372 103 -106 83 -814 207 -230 177 -280 75 -966 51 -823 77 -102 105 -394 139 -112 81 -1292 75 -727 183 -734 51 -590 83 -242 77 -1674 105 -562 107 -484 103 -104 107 -2114 77 -2326 51 -1052 207 -594 129 -232 177 -895 51 -506 203 -671 75 -206 101 -328 77 -104 105 -132 77 -370 186 -82 79 -846 77 -1272 53 -1609 177 -406 51 -226 121 -330 51 -280 73 -3094 75 -802 236 -3347 53 -2218 51 -1176 107 -212 75 -1460 51 -714 81 -1643 105 -4782 55 -5096 51 -7167 53 -17412 53 -6530 51 -20019 51 -12370 71 -442 103 -10796 55 -1320 105 -660 51 -1854 135 -16801 77 -5863 87 -12342 119 -24656 81 -7111 101 -15641 79 -3617 75 -10578 127 -5573 77 -16152 53 -5624 51 -13975 71 -7720 79 -3760 51 -9739 77 -1892 73 -2638 153 -4570 51 -5265 53 -3429 79 -1982 53 -2154 51 -7158 53 -12468 161 -12934 79 -14244 77 -3871 105 -2482 79 -4568 99 -218 79 -17125 53 -2368 53 -10101 55 -15958 81 -2358 109 -3584 51 -6886 85 -6834 51 -4154 53 -218 53 -826 55 -7583 51 -11429 216 -1346 71 -1856 79 -982 55 -2072 51 -4033 105 -7186 79 -1506 81 -8082 53 -6530 83 -6380 109 -192 135 -6058 51 -3274 79 -6105 57 -18103 53 -1142 55 -4687 57 -12931 99 -344 53 -9300 79 -7717 75 -3774 81 -3691 105 -2780 51 -2764 75 -1030 79 -29043 79 -3611 53 -1934 79 -4819 75 -6538 53 -7104 53 -3542 55 -1969 53 -2426 105 -7239 81 -516 79 -14563 123 -2246 53 -3012 71 -900 55 -1196 51 -7049 51 -1790 53 -10358 53 -3988 81 -1214 107 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 4759ed4db..0a7d529ce 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -122,4 +122,9 @@ RAW_Data: -130 84629 -16530 199 -594 163 -562 65 -164 65 -230 1383 -100 1031 -66 RAW_Data: 12477 16271 -64 12623 -102 40819 -98 3729 -66 14371 -66 14943 -64 5931 -66 11147 -68 74641 -102 54299 -70 18441 -66 82993 -100 66161 -68 61869 -66 6627 -66 12987 -68 30427 -68 25761 -98 6305 -66 5019 -64 30857 -132 23929 -68 25129 -39378 317 -2020 311 -2010 2033 -312 2017 -282 325 -2018 291 -2024 2035 -316 2023 -276 319 -2028 297 -2032 2029 -284 2023 -314 321 -2016 319 -2012 2003 -310 2015 -318 321 -1984 327 -16000 351 -1974 321 -2020 2041 -276 2047 -288 327 -1992 327 -2000 2055 -282 2053 -274 305 -2022 301 -2014 2049 -286 2055 -274 319 -1992 329 -2006 2065 -282 2023 -316 323 -1988 303 -16008 323 -2014 315 -1990 2053 -284 2061 -274 319 -1988 319 -2038 2033 -286 2055 -264 339 -2008 289 -2034 2035 -284 2061 -262 339 -2008 287 -2040 2037 -286 2035 -268 347 -2006 317 -15988 311 -2014 343 -2014 2027 -300 2031 -258 311 -2024 323 -2028 2023 -280 2051 -318 285 -2024 309 -2002 2039 -312 2017 -318 289 -2020 293 -2028 2035 -316 2023 -276 321 -2030 299 -15982 345 -1988 345 -2014 2029 -268 2069 -258 337 -1998 321 -2024 2025 -320 2025 -276 321 -1994 331 -2000 2057 -282 2043 -282 305 -2034 291 -2024 2039 -320 2019 -278 323 -1992 333 -15976 389 -1978 321 -1986 2069 -276 2053 -288 303 -2020 315 -1980 2067 -258 2075 -258 337 -1996 321 -2030 2027 -284 2059 -274 319 -2004 319 -2016 2033 -282 2059 -264 345 -2006 289 -16006 355 -1984 315 -2018 2033 -312 2015 -284 327 -2000 329 -2000 2063 -282 2049 -284 327 -1984 319 -2018 2035 -284 2057 -264 343 -2004 289 -2032 2059 -280 2019 -316 323 -1984 321 -15968 387 -1978 321 -1984 2069 -276 2049 -288 325 -1996 303 -2004 2055 -284 2049 -278 325 -2018 321 -1984 2075 -276 2049 -288 327 -1990 325 -1996 2031 -318 2025 -278 323 -2018 289 -16010 357 -1982 315 -2018 2035 -278 2053 -288 307 -2022 321 -2000 2049 -274 2045 -284 327 -2022 311 -2014 2033 -276 2053 -286 327 -2000 323 -2000 2061 -282 2015 -316 325 -2002 289 -15994 353 -1980 357 -1990 2035 -312 2015 -286 327 -2020 289 -2022 2033 -318 2019 -278 323 -2004 319 -2016 2059 -282 2023 -316 327 -1970 321 -2018 2059 -280 2019 -318 325 -1972 321 -15988 353 -1982 357 -1972 2071 -276 2051 -288 327 -1988 323 -1996 2061 -280 2053 -284 325 -1984 321 -2014 2031 -282 2059 -276 321 -2018 289 -2036 2031 -282 2059 -276 321 -2018 319 -15984 341 -1984 343 -2016 2029 -298 2033 -258 309 -2028 321 -2032 2035 -284 2017 -298 337 -2008 289 -2034 2027 -314 2023 -310 285 -2016 321 -2014 2035 -282 2027 -308 317 -2026 297 -15982 357 -1984 345 -1982 2067 -264 2057 -258 341 -1996 317 -2026 2057 -282 2017 -318 325 -1972 319 -2018 2059 -280 2029 -302 315 -2006 319 -2006 2059 -274 2047 -276 307 RAW_Data: -2024 311 -15984 349 -2004 317 -2012 2029 -276 2047 -312 305 -2018 311 -2018 2037 -258 2077 -258 337 -1998 321 -2026 2031 -278 2043 -284 327 -2020 311 -2018 2031 -278 2051 -288 325 -2004 323 -15962 353 -2018 317 -2014 2007 -308 2019 -320 287 -2024 325 -1998 2035 -314 2025 -302 311 -2004 319 -2010 2027 -312 2011 -310 309 -2028 303 -2018 2027 -304 2007 -294 309 -2024 323 -16002 361 -1946 347 -2008 2027 -286 2045 -312 325 -1978 319 -2024 2043 -276 2049 -286 325 -1988 341 -1978 2061 -278 2049 -284 327 -1990 321 -2020 2029 -318 2021 -278 323 -2008 321 -15990 355 -1982 355 -1984 2031 -284 2049 -278 325 -2018 321 -2000 2047 -276 2049 -286 327 -1994 341 -1976 2067 -274 2043 -284 303 -2018 341 -1982 2061 -266 2069 -258 339 -1998 321 -16002 311 -2014 329 -2012 2027 -318 1999 -298 339 -2008 287 -2042 2031 -282 2027 -306 317 -2012 291 -2044 2037 -284 2033 -302 315 -2004 321 -2012 2037 -282 2027 -306 317 -2028 297 -15980 345 -2018 285 -2026 2037 -320 2017 -278 323 -2024 299 -2002 2069 -278 2055 -286 325 -2002 289 -2024 2037 -282 2063 -276 321 -2016 287 -2036 2025 -320 2023 -278 323 -2018 287 -16006 355 -1982 355 -1986 2033 -302 2039 -282 307 -2032 309 -2014 2043 -264 2057 -258 341 -1992 319 -2036 2033 -284 2029 -306 319 -2000 319 -2014 2035 -282 2061 -266 343 -2006 289 -16018 331 -2010 313 -2014 2021 -320 2017 -278 323 -2010 321 -2016 2037 -284 2033 -304 317 -2018 287 -2036 2037 -284 2025 -296 339 -1978 321 -2028 2057 -282 2021 -278 359 -1972 321 -15990 355 -1978 355 -1990 2035 -300 2015 -312 305 -2016 315 -2016 2053 -290 2013 -316 277 -2020 353 -1980 2059 -256 2077 -276 307 -2020 311 -2012 2047 -258 2073 -256 341 -1998 321 -15976 369 -1976 313 -2018 2051 -280 2043 -290 317 -2004 321 -2024 2023 -282 2053 -282 327 -2020 313 -2020 2035 -278 2055 -284 325 -1986 321 -2016 2033 -280 2049 -282 325 -2020 313 -15986 315 -2026 319 -2028 2003 -318 2013 -294 339 -2008 289 -2032 2027 -316 2019 -302 311 -2004 321 -2014 2033 -314 1995 -308 317 -2028 297 -2032 2035 -276 2023 -316 321 -2014 289 -15998 347 -2014 283 -2020 2035 -292 2031 -288 311 -2024 321 -2036 2001 -310 2027 -318 275 -2054 277 -2026 2029 -296 2027 -292 311 -2024 321 -2030 2031 -282 2033 -304 313 -2004 321 -15992 329 -2010 349 -1980 2037 -292 2051 -256 339 -1998 319 -2034 2029 -286 2055 -264 339 -1978 321 -2030 2027 -280 2043 -316 327 -1984 315 -2016 2063 -278 2041 -288 327 -1990 325 -15964 389 -1978 319 -1984 2063 -256 2055 -292 307 -2016 323 -2028 2027 -286 2057 -274 319 -2010 319 -2010 2033 -282 2061 -276 321 -2018 289 -2032 2027 -318 2021 -278 321 -2020 319 -15974 355 -1980 357 -2000 2035 RAW_Data: -254 2079 -276 309 -2016 309 -2012 2035 -296 2063 -258 337 -1992 321 -2030 2037 -286 2027 -294 333 -1978 321 -2034 2029 -286 2031 -306 315 -2008 321 -15972 355 -1984 315 -2014 2037 -310 2011 -318 323 -1984 329 -2002 2033 -316 2029 -278 323 -2026 299 -2030 2035 -278 2019 -316 325 -1980 323 -2018 2053 -252 2075 -280 327 -1984 355 -15954 345 -2008 309 -2016 2045 -266 2065 -258 341 -235740 101 -202 65 -734 133 -372 401 -68 269 -236 505 -68 235 -234 875 -68 13969 -100 14297 -70 3863 -96 59337 -104 11859 -68 17409 -68 7317 -66 11443 -64 15589 -66 4381 -98 32297 -168 45445 -100 59295 -100 41417 -66 1539 -66 23001 - +RAW_Data: 171 -316 311 -154 187 -292 343 -134 337 -136 199 -286 311 -182 157 -294 327 -160 171 -316 161 -312 159 -314 333 -170 311 -164 141 -324 305 -164 299 -176 301 -170 167 -340 133 -338 163 -312 159 -294 189 -298 165 -314 311 -180 155 -294 189 -300 165 -312 187 -284 189 -312 159 -294 189 -296 167 -314 161 -310 189 -312 159 -292 189 -296 167 -312 161 -312 159 -314 193 -268 175 -304 193 -314 163 -312 159 -312 193 -294 495 -458 161 -338 301 -168 165 -304 331 -134 199 -286 309 -184 309 -170 141 -318 331 -162 143 -316 309 -182 157 -294 189 -302 163 -312 309 -184 311 -170 141 -318 331 -162 299 -150 319 -196 139 -314 165 -334 137 -340 159 -312 161 -302 149 -318 331 -162 173 -312 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -300 193 -284 187 -284 189 -312 159 -292 189 -298 167 -312 161 -312 189 -300 173 -294 195 -282 191 -310 485 -472 167 -300 331 -134 171 -312 333 -170 169 -290 331 -162 299 -176 155 -300 333 -162 171 -300 323 -150 145 -340 159 -320 167 -302 319 -150 319 -166 169 -312 331 -162 299 -150 319 -194 139 -314 165 -308 163 -340 133 -338 163 -312 157 -296 327 -160 171 -316 163 -310 161 -312 163 -298 177 -302 193 -314 163 -310 161 -312 163 -300 173 -300 169 -318 177 -290 189 -300 165 -312 161 -312 189 -284 185 -292 189 -300 191 -286 187 -284 191 -312 471 -486 167 -314 313 -152 159 -300 335 -162 169 -308 319 -150 319 -166 169 -312 331 -162 143 -314 311 -180 157 -294 189 -300 165 -314 309 -182 311 -168 141 -318 333 -162 299 -174 295 -194 141 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -160 171 -316 161 -312 159 -314 191 -270 201 -278 193 -314 163 -310 161 -312 163 -300 175 -300 169 -316 177 -292 189 -300 165 -312 161 -312 189 -284 183 -294 189 -298 193 -284 187 -312 163 -312 497 -460 145 -320 325 -168 171 -290 333 -162 171 -314 305 -160 317 -168 169 -290 333 -162 173 -312 283 -182 159 -294 189 -302 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 321 -194 141 -312 167 -334 135 -340 161 -310 163 -312 159 -294 327 -160 171 -316 163 -310 161 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -300 165 -312 161 -310 189 -284 185 -292 189 -300 191 -286 187 -312 161 -300 487 -484 151 -318 335 -138 169 -322 305 -164 171 -314 305 -190 295 -166 171 -290 333 -162 173 -312 283 -182 159 -296 191 -300 +RAW_Data: 165 -312 333 -160 311 -170 141 -318 331 -164 299 -148 321 -194 139 -316 165 -336 135 -340 133 -338 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -298 193 -310 163 -312 159 -312 163 -300 175 -296 193 -312 163 -312 159 -312 163 -300 175 -298 167 -320 175 -290 191 -296 193 -286 187 -310 163 -300 175 -296 501 -458 187 -288 347 -154 151 -316 325 -162 171 -316 313 -152 301 -194 141 -316 331 -162 143 -314 311 -182 155 -294 189 -302 163 -314 309 -182 311 -168 143 -318 331 -162 301 -174 295 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -158 173 -314 163 -312 159 -306 173 -314 165 -306 191 -284 189 -284 189 -312 157 -294 191 -300 163 -314 187 -284 189 -284 187 -292 189 -296 165 -314 161 -312 189 -284 185 -294 189 -298 193 -286 485 -492 167 -298 323 -150 175 -302 331 -164 171 -300 321 -150 317 -166 167 -308 331 -134 171 -316 309 -182 129 -318 189 -302 163 -314 309 -182 311 -170 141 -318 331 -162 301 -148 321 -194 139 -314 167 -334 137 -338 161 -310 163 -312 159 -294 327 -160 171 -316 161 -312 159 -312 193 -270 175 -304 193 -314 163 -312 159 -312 161 -314 161 -296 189 -304 165 -312 187 -284 189 -276 173 -318 195 -278 193 -284 187 -312 163 -300 175 -298 169 -318 511 -460 147 -318 327 -168 169 -292 331 -164 171 -314 305 -160 315 -168 171 -290 333 -162 171 -314 283 -182 159 -294 189 -300 165 -314 307 -184 311 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 157 -294 327 -160 171 -316 163 -310 161 -304 175 -314 167 -304 191 -286 187 -284 189 -284 187 -292 189 -300 165 -312 189 -284 187 -286 185 -294 189 -296 165 -314 161 -312 187 -286 185 -294 189 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -168 171 -292 331 -164 299 -174 151 -316 325 -162 171 -316 289 -176 151 -316 187 -296 167 -312 311 -180 307 -170 141 -318 331 -162 299 -150 319 -196 139 -314 165 -334 137 -340 159 -312 161 -302 149 -320 329 -164 171 -314 159 -312 163 -300 175 -298 193 -310 163 -312 161 -310 163 -312 161 -296 189 -302 191 -286 187 -284 189 -312 159 -292 189 -296 167 -314 161 -310 189 -284 187 -292 189 -300 193 -284 485 -494 167 -296 323 -150 175 -312 313 -170 169 -292 333 -162 299 -176 151 -314 327 -160 171 -316 291 -176 149 -316 189 -296 165 -314 309 -182 307 -168 141 -318 331 -164 299 -148 321 -194 141 -314 165 -334 137 -338 161 -312 +RAW_Data: 161 -302 147 -320 331 -162 171 -314 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -296 195 -284 189 -284 189 -312 159 -296 513 -468 159 -300 333 -162 171 -300 323 -150 171 -314 325 -162 311 -164 171 -314 305 -160 159 -296 327 -160 171 -316 161 -312 161 -312 335 -170 311 -164 141 -324 321 -154 299 -194 309 -164 143 -326 167 -314 161 -312 159 -312 163 -302 173 -300 331 -162 173 -312 161 -312 163 -300 175 -300 167 -320 153 -312 191 -296 167 -312 161 -312 189 -312 159 -292 189 -298 167 -312 161 -312 159 -314 193 -268 177 -302 193 -316 161 -312 159 -312 193 -294 497 -456 187 -312 303 -166 165 -306 331 -132 201 -286 309 -182 313 -168 143 -318 331 -162 143 -314 311 -182 157 -294 189 -302 165 -312 309 -182 311 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -338 161 -312 161 -300 149 -320 331 -162 171 -314 161 -310 163 -302 173 -298 193 -310 165 -310 161 -310 163 -312 161 -296 189 -300 193 -286 187 -284 189 -312 157 -294 189 -298 165 -314 161 -310 189 -284 187 -292 189 -300 193 -284 485 -494 167 -298 321 -150 171 -318 323 -162 171 -314 289 -176 297 -194 141 -314 331 -162 143 -316 309 -182 155 -294 189 -302 163 -314 309 -182 311 -168 143 -318 331 -162 301 -148 321 -194 139 -314 167 -334 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -300 175 -296 193 -312 163 -312 159 -312 163 -300 175 -298 167 -320 175 -290 191 -296 193 -286 187 -310 163 -312 161 -296 513 -468 159 -300 333 -162 171 -302 321 -150 175 -300 333 -162 311 -162 171 -316 289 -176 153 -314 327 -160 171 -316 163 -312 159 -312 307 -168 335 -138 169 -320 307 -164 297 -176 301 -194 141 -318 165 -336 137 -338 133 -338 163 -312 159 -294 327 -160 171 -316 161 -312 161 -312 163 -298 177 -302 169 -318 177 -292 189 -298 167 -312 189 -284 189 -312 157 -294 189 -298 167 -312 161 -312 159 -312 193 -270 203 -302 169 -314 161 -312 189 -310 467 -484 145 -318 327 -168 143 -316 331 -162 173 -312 307 -160 313 -170 141 -318 331 -164 143 -342 281 -184 157 -294 189 -302 165 -312 307 -184 313 -168 141 -320 331 -162 299 -150 319 -194 141 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -158 173 -314 163 -310 161 -312 165 -298 175 -304 193 -312 163 -312 159 -312 +RAW_Data: 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 185 -292 189 -298 193 -284 189 -310 163 -312 497 -460 145 -320 325 -170 169 -290 333 -162 171 -314 307 -158 317 -168 169 -290 333 -162 171 -314 281 -182 159 -296 189 -300 165 -312 309 -182 313 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 135 -338 161 -312 159 -294 327 -160 173 -314 163 -312 159 -312 163 -300 175 -302 195 -312 163 -312 159 -312 163 -300 175 -298 169 -318 175 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 193 -284 187 -312 161 -314 471 -486 167 -314 313 -152 159 -300 335 -162 169 -308 321 -156 329 -170 127 -318 321 -176 155 -300 333 -164 169 -302 165 -314 161 -310 329 -168 299 -166 151 -328 311 -154 331 -168 299 -178 143 -318 153 -322 167 -332 149 -320 151 -318 165 -304 321 -156 181 -290 189 -300 173 -294 177 -294 189 -302 173 -294 177 -294 189 -302 173 -294 177 -318 193 -278 173 -294 179 -292 191 -302 173 -294 177 -294 189 -302 173 -320 177 -294 195 -278 175 -318 491 -460 163 -314 333 -158 159 -294 327 -160 171 -316 311 -180 307 -170 141 -318 331 -162 143 -316 309 -182 157 -294 189 -302 165 -312 309 -182 313 -168 141 -318 331 -164 299 -148 321 -194 141 -314 165 -334 137 -338 135 -338 161 -312 159 -294 329 -158 173 -314 163 -310 161 -306 173 -314 165 -304 193 -284 187 -286 189 -276 197 -294 193 -310 163 -312 161 -310 163 -300 175 -296 193 -310 165 -284 187 -310 163 -300 175 -300 169 -318 177 -316 483 -466 187 -292 341 -134 171 -308 319 -150 179 -300 333 -164 309 -162 171 -316 313 -152 153 -316 327 -160 171 -316 163 -310 161 -312 307 -166 337 -136 171 -322 305 -164 299 -174 301 -194 141 -318 165 -336 137 -338 161 -310 163 -300 149 -320 331 -162 171 -314 161 -312 163 -300 173 -296 195 -310 163 -312 159 -312 163 -312 159 -296 189 -302 165 -312 189 -284 189 -284 185 -294 189 -296 165 -314 161 -310 189 -284 187 -294 189 -298 193 -284 485 -494 167 -298 321 -150 177 -312 313 -168 171 -290 333 -162 299 -176 151 -316 325 -162 171 -316 289 -176 151 -314 189 -296 165 -314 309 -182 305 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -340 133 -338 161 -302 149 -320 329 -164 171 -286 187 -312 163 -300 173 -298 193 -310 163 -312 159 -312 163 -312 159 -296 189 -302 191 -286 187 -284 189 -312 159 -292 191 -296 165 -314 161 -310 189 -284 187 -292 +RAW_Data: 189 -300 193 -284 485 -494 167 -298 321 -150 177 -300 327 -150 167 -328 305 -160 319 -168 171 -290 333 -162 171 -314 281 -184 159 -296 189 -300 165 -314 307 -184 311 -170 141 -318 333 -162 299 -150 319 -194 139 -314 167 -334 135 -340 133 -338 163 -312 159 -294 327 -158 173 -314 163 -312 159 -312 165 -298 177 -302 193 -314 163 -310 161 -312 163 -300 173 -300 167 -318 177 -292 189 -300 165 -312 161 -312 187 -284 185 -292 189 -300 191 -286 187 -284 189 -300 487 -484 149 -320 333 -138 171 -322 321 -154 151 -316 327 -160 311 -164 173 -312 307 -160 161 -298 355 -132 173 -314 163 -310 161 -312 335 -170 311 -164 143 -322 307 -164 323 -150 301 -196 141 -318 165 -334 137 -338 161 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 173 -298 195 -310 163 -312 159 -312 163 -312 159 -296 189 -300 193 -284 189 -284 189 -284 185 -294 189 -296 165 -314 161 -312 189 -284 185 -294 189 -298 193 -286 485 -468 193 -296 323 -150 147 -340 313 -168 171 -292 331 -164 299 -174 151 -316 325 -160 173 -316 289 -176 149 -316 189 -294 165 -314 309 -182 307 -170 141 -318 331 -164 299 -148 321 -194 139 -314 167 -306 165 -338 133 -338 163 -312 159 -294 327 -160 173 -314 163 -312 161 -310 165 -300 175 -300 169 -318 177 -290 189 -298 165 -314 187 -284 189 -312 159 -294 189 -298 165 -314 161 -310 161 -306 173 -316 193 -280 191 -312 159 -312 163 -300 515 -460 161 -312 305 -190 135 -328 329 -134 201 -286 309 -182 311 -168 143 -318 331 -162 143 -316 309 -182 157 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -334 137 -340 159 -312 163 -300 149 -318 331 -162 173 -312 161 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 173 -296 193 -312 163 -312 159 -312 163 -312 161 -298 189 -300 165 -312 161 -312 189 -312 159 -292 191 -300 191 -286 485 -468 193 -298 323 -148 147 -342 323 -160 173 -314 289 -176 297 -196 139 -314 331 -162 143 -314 311 -180 157 -292 191 -300 165 -312 311 -182 309 -170 141 -318 333 -162 299 -150 319 -194 141 -314 165 -334 137 -338 161 -312 161 -312 159 -294 329 -158 173 -314 163 -310 161 -312 165 -298 175 -304 193 -312 163 -310 161 -310 163 -302 173 -300 169 -318 175 -292 189 -300 165 -312 161 -310 189 -278 173 -316 195 -280 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -328 329 -134 199 -288 309 -182 311 -168 143 -318 +RAW_Data: 331 -162 143 -316 309 -182 157 -292 191 -300 165 -312 309 -182 313 -168 141 -318 331 -164 299 -174 295 -194 141 -314 165 -334 137 -340 133 -338 163 -312 159 -292 327 -160 171 -316 163 -310 161 -312 165 -298 175 -304 193 -312 163 -312 159 -312 163 -300 175 -300 169 -316 177 -292 189 -298 167 -312 161 -310 189 -278 173 -316 193 -282 191 -312 159 -312 163 -300 515 -460 163 -310 305 -190 137 -326 331 -132 201 -286 309 -184 309 -170 141 -318 333 -162 143 -314 311 -180 159 -294 189 -300 165 -312 309 -184 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 135 -340 159 -312 163 -300 149 -320 329 -164 171 -314 159 -312 163 -300 175 -296 195 -310 163 -312 159 -312 163 -300 175 -294 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 153 -314 191 -296 193 -286 187 -284 189 -312 161 -294 509 -468 159 -298 335 -162 169 -304 323 -150 175 -300 335 -162 311 -160 173 -316 313 -152 151 -316 327 -160 171 -316 163 -312 159 -312 307 -168 335 -138 169 -322 305 -164 299 -176 299 -194 141 -316 167 -334 137 -340 159 -312 161 -302 147 -320 331 -162 173 -312 161 -312 163 -300 175 -296 193 -310 165 -310 161 -312 161 -302 173 -296 195 -310 163 -312 161 -310 163 -300 175 -298 169 -318 177 -290 189 -296 193 -286 187 -310 163 -300 175 -296 501 -484 161 -288 347 -154 151 -316 325 -160 173 -314 313 -152 301 -196 141 -314 331 -162 143 -316 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -318 331 -162 301 -148 319 -196 139 -314 165 -336 137 -338 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 163 -298 177 -302 193 -314 163 -312 159 -312 163 -300 175 -298 169 -318 177 -290 191 -298 165 -314 161 -310 189 -284 193 -292 179 -308 167 -314 161 -312 189 -302 481 -460 173 -320 303 -168 169 -294 331 -164 171 -314 307 -160 319 -168 169 -292 331 -162 143 -342 283 -182 159 -294 189 -302 165 -312 309 -184 311 -168 143 -318 331 -162 299 -150 319 -194 141 -314 165 -336 135 -340 133 -338 163 -312 159 -294 327 -158 173 -316 161 -312 159 -312 165 -298 177 -302 193 -312 163 -312 161 -310 163 -314 161 -296 189 -302 165 -312 187 -284 189 -284 185 -294 189 -296 165 -314 187 -284 189 -302 173 -294 195 -310 491 -458 163 -318 319 -156 153 -314 327 -160 171 -316 311 -152 327 -170 141 -316 331 -164 143 -314 309 -182 157 -294 189 -300 165 -314 309 -182 311 -168 143 -316 333 -162 299 -150 diff --git a/lib/subghz/blocks/math.c b/lib/subghz/blocks/math.c index 55ad7cc80..fca50c8f8 100644 --- a/lib/subghz/blocks/math.c +++ b/lib/subghz/blocks/math.c @@ -7,3 +7,11 @@ uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit) { } return key_reverse; } + +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit) { + uint8_t parity = 0; + for(uint8_t i = 0; i < count_bit; i++) { + parity += bit_read(key, i); + } + return parity & 0x01; +} \ No newline at end of file diff --git a/lib/subghz/blocks/math.h b/lib/subghz/blocks/math.h index fde5191bd..85b146ebc 100644 --- a/lib/subghz/blocks/math.h +++ b/lib/subghz/blocks/math.h @@ -17,3 +17,11 @@ * @return Reverse data */ uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); + +/** + * Get parity the data bitwise. + * @param key In data + * @param count_bit number of data bits + * @return parity + */ +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit); diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index ef352bf60..9bf87ea2b 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -455,7 +455,7 @@ void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output string_cat_printf( output, - "%s %dbit\r\n" + "%s %db\r\n" "Key:0x%lX%08lX\r\n" "Btn:%lX\r\n" "DIP:" DIP_PATTERN "\r\n", diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c new file mode 100644 index 000000000..292229130 --- /dev/null +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -0,0 +1,399 @@ +#include "honeywell_wdb.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolHoneywellWDB" + +/* + * + * https://github.com/klohner/honeywell-wireless-doorbell + * + */ + +static const SubGhzBlockConst subghz_protocol_honeywell_wdb_const = { + .te_short = 160, + .te_long = 320, + .te_delta = 60, + .min_count_bit_for_found = 48, +}; + +struct SubGhzProtocolDecoderHoneywell_WDB { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + const char* device_type; + const char* alert; + uint8_t secret_knock; + uint8_t relay; + uint8_t lowbat; +}; + +struct SubGhzProtocolEncoderHoneywell_WDB { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + Honeywell_WDBDecoderStepReset = 0, + Honeywell_WDBDecoderStepFoundStartBit, + Honeywell_WDBDecoderStepSaveDuration, + Honeywell_WDBDecoderStepCheckDuration, +} Honeywell_WDBDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_honeywell_wdb_decoder = { + .alloc = subghz_protocol_decoder_honeywell_wdb_alloc, + .free = subghz_protocol_decoder_honeywell_wdb_free, + + .feed = subghz_protocol_decoder_honeywell_wdb_feed, + .reset = subghz_protocol_decoder_honeywell_wdb_reset, + + .get_hash_data = subghz_protocol_decoder_honeywell_wdb_get_hash_data, + .serialize = subghz_protocol_decoder_honeywell_wdb_serialize, + .deserialize = subghz_protocol_decoder_honeywell_wdb_deserialize, + .get_string = subghz_protocol_decoder_honeywell_wdb_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_honeywell_wdb_encoder = { + .alloc = subghz_protocol_encoder_honeywell_wdb_alloc, + .free = subghz_protocol_encoder_honeywell_wdb_free, + + .deserialize = subghz_protocol_encoder_honeywell_wdb_deserialize, + .stop = subghz_protocol_encoder_honeywell_wdb_stop, + .yield = subghz_protocol_encoder_honeywell_wdb_yield, +}; + +const SubGhzProtocol subghz_protocol_honeywell_wdb = { + .name = SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | + SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_honeywell_wdb_decoder, + .encoder = &subghz_protocol_honeywell_wdb_encoder, +}; + +void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderHoneywell_WDB* instance = + malloc(sizeof(SubGhzProtocolEncoderHoneywell_WDB)); + + instance->base.protocol = &subghz_protocol_honeywell_wdb; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_honeywell_wdb_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderHoneywell_WDB* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + * @return true On success + */ +static bool subghz_protocol_encoder_honeywell_wdb_get_upload( + SubGhzProtocolEncoderHoneywell_WDB* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + //Send header + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_honeywell_wdb_const.te_short * 3); + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_honeywell_wdb_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_honeywell_wdb_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_honeywell_wdb_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_honeywell_wdb_const.te_long); + } + } + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_honeywell_wdb_const.te_short * 3); + return true; +} + +bool subghz_protocol_encoder_honeywell_wdb_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderHoneywell_WDB* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_honeywell_wdb_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_honeywell_wdb_stop(void* context) { + SubGhzProtocolEncoderHoneywell_WDB* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_honeywell_wdb_yield(void* context) { + SubGhzProtocolEncoderHoneywell_WDB* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_honeywell_wdb_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderHoneywell_WDB* instance = + malloc(sizeof(SubGhzProtocolDecoderHoneywell_WDB)); + instance->base.protocol = &subghz_protocol_honeywell_wdb; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_honeywell_wdb_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + free(instance); +} + +void subghz_protocol_decoder_honeywell_wdb_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + instance->decoder.parser_step = Honeywell_WDBDecoderStepReset; +} + +void subghz_protocol_decoder_honeywell_wdb_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + switch(instance->decoder.parser_step) { + case Honeywell_WDBDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_honeywell_wdb_const.te_short * 3) < + subghz_protocol_honeywell_wdb_const.te_delta)) { + //Found header Honeywell_WDB + instance->decoder.decode_count_bit = 0; + instance->decoder.decode_data = 0; + instance->decoder.parser_step = Honeywell_WDBDecoderStepSaveDuration; + } + break; + case Honeywell_WDBDecoderStepSaveDuration: + if(level) { //save interval + if(DURATION_DIFF(duration, subghz_protocol_honeywell_wdb_const.te_short * 3) < + subghz_protocol_honeywell_wdb_const.te_delta) { + if((instance->decoder.decode_count_bit == + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found) && + ((instance->decoder.decode_data & 0x01) == + subghz_protocol_blocks_get_parity( + instance->decoder.decode_data >> 1, + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found - 1))) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = Honeywell_WDBDecoderStepReset; + break; + } + instance->decoder.te_last = duration; + instance->decoder.parser_step = Honeywell_WDBDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = Honeywell_WDBDecoderStepReset; + } + break; + case Honeywell_WDBDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_honeywell_wdb_const.te_short) < + subghz_protocol_honeywell_wdb_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_honeywell_wdb_const.te_long) < + subghz_protocol_honeywell_wdb_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = Honeywell_WDBDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_honeywell_wdb_const.te_long) < + subghz_protocol_honeywell_wdb_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_honeywell_wdb_const.te_short) < + subghz_protocol_honeywell_wdb_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = Honeywell_WDBDecoderStepSaveDuration; + } else + instance->decoder.parser_step = Honeywell_WDBDecoderStepReset; + } else { + instance->decoder.parser_step = Honeywell_WDBDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzProtocolDecoderHoneywell_WDB* instance + */ +static void subghz_protocol_honeywell_wdb_check_remote_controller( + SubGhzProtocolDecoderHoneywell_WDB* instance) { + /* + * + * Frame bits used in Honeywell RCWL300A, RCWL330A, Series 3, 5, 9 and all Decor Series Wireless Chimes + * 0000 0000 1111 1111 2222 2222 3333 3333 4444 4444 5555 5555 + * 7654 3210 7654 3210 7654 3210 7654 3210 7654 3210 7654 3210 + * XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XX.. XXX. .... KEY DATA (any change and receiver doesn't seem to recognize signal) + * XXXX XXXX XXXX XXXX XXXX .... .... .... .... .... .... .... KEY ID (different for each transmitter) + * .... .... .... .... .... 0000 00.. 0000 0000 00.. 000. .... KEY UNKNOWN 0 (always 0 in devices I've tested) + * .... .... .... .... .... .... ..XX .... .... .... .... .... DEVICE TYPE (10 = doorbell, 01 = PIR Motion sensor) + * .... .... .... .... .... .... .... .... .... ..XX ...X XXX. FLAG DATA (may be modified for possible effects on receiver) + * .... .... .... .... .... .... .... .... .... ..XX .... .... ALERT (00 = normal, 01 or 10 = right-left halo light pattern, 11 = full volume alarm) + * .... .... .... .... .... .... .... .... .... .... ...X .... SECRET KNOCK (0 = default, 1 if doorbell is pressed 3x rapidly) + * .... .... .... .... .... .... .... .... .... .... .... X... RELAY (1 if signal is a retransmission of a received transmission, only some models) + * .... .... .... .... .... .... .... .... .... .... .... .X.. FLAG UNKNOWN (0 = default, but 1 is accepted and I don't observe any effects) + * .... .... .... .... .... .... .... .... .... .... .... ..X. LOWBAT (1 if battery is low, receiver gives low battery alert) + * .... .... .... .... .... .... .... .... .... .... .... ...X PARITY (LSB of count of set bits in previous 47 bits) + * + */ + + instance->generic.serial = (instance->generic.data >> 28) & 0xFFFFF; + switch((instance->generic.data >> 20) & 0x3) { + case 0x02: + instance->device_type = "Doorbell"; + break; + case 0x01: + instance->device_type = "PIR-Motion"; + break; + default: + instance->device_type = "Unknown"; + break; + } + + switch((instance->generic.data >> 16) & 0x3) { + case 0x00: + instance->alert = "Normal"; + break; + case 0x01: + case 0x02: + instance->alert = "High"; + break; + case 0x03: + instance->alert = "Full"; + break; + default: + instance->alert = "Unknown"; + break; + } + + instance->secret_knock = (uint8_t)((instance->generic.data >> 4) & 0x1); + instance->relay = (uint8_t)((instance->generic.data >> 3) & 0x1); + instance->lowbat = (uint8_t)((instance->generic.data >> 1) & 0x1); +} + +uint8_t subghz_protocol_decoder_honeywell_wdb_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_honeywell_wdb_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_honeywell_wdb_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_honeywell_wdb_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_honeywell_wdb_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderHoneywell_WDB* instance = context; + subghz_protocol_honeywell_wdb_check_remote_controller(instance); + + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%05lX\r\n" + "DT:%s Al:%s\r\n" + "SK:%01lX R:%01lX LBat:%01lX\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)((instance->generic.data >> 32) & 0xFFFFFFFF), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + instance->device_type, + instance->alert, + instance->secret_knock, + instance->relay, + instance->lowbat); +} diff --git a/lib/subghz/protocols/honeywell_wdb.h b/lib/subghz/protocols/honeywell_wdb.h new file mode 100644 index 000000000..012b36996 --- /dev/null +++ b/lib/subghz/protocols/honeywell_wdb.h @@ -0,0 +1,111 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME "Honeywell" + +typedef struct SubGhzProtocolDecoderHoneywell_WDB SubGhzProtocolDecoderHoneywell_WDB; +typedef struct SubGhzProtocolEncoderHoneywell_WDB SubGhzProtocolEncoderHoneywell_WDB; + +extern const SubGhzProtocolDecoder subghz_protocol_honeywell_wdb_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_honeywell_wdb_encoder; +extern const SubGhzProtocol subghz_protocol_honeywell_wdb; + +/** + * Allocate SubGhzProtocolEncoderHoneywell_WDB. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderHoneywell_WDB* pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + */ +void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderHoneywell_WDB. + * @param context Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + */ +void subghz_protocol_encoder_honeywell_wdb_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_honeywell_wdb_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + */ +void subghz_protocol_encoder_honeywell_wdb_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderHoneywell_WDB instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_honeywell_wdb_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderHoneywell_WDB. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderHoneywell_WDB* pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + */ +void* subghz_protocol_decoder_honeywell_wdb_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderHoneywell_WDB. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + */ +void subghz_protocol_decoder_honeywell_wdb_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderHoneywell_WDB. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + */ +void subghz_protocol_decoder_honeywell_wdb_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_honeywell_wdb_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_honeywell_wdb_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderHoneywell_WDB. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzPresetDefinition + * @return true On success + */ +bool subghz_protocol_decoder_honeywell_wdb_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzPresetDefinition* preset); + +/** + * Deserialize data SubGhzProtocolDecoderHoneywell_WDB. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_honeywell_wdb_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderHoneywell_WDB instance + * @param output Resulting text + */ +void subghz_protocol_decoder_honeywell_wdb_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 893947304..19b03cebc 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -1,16 +1,17 @@ #include "registry.h" const SubGhzProtocol* subghz_protocol_registry[] = { - &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, - &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, - &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, - &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, - &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, - &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, - &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, - &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, - &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, + &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, + &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, + &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, + &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, + &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, + &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, + &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, + &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, + &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, + &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, + &subghz_protocol_honeywell_wdb, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 97a1376d6..d75695132 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -32,6 +32,7 @@ #include "bett.h" #include "doitrand.h" #include "phoenix_v2.h" +#include "honeywell_wdb.h" /** * Registration by name SubGhzProtocol. From 874eb46c93864fad91adb2b805da8bd486b5071c Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 11 Aug 2022 17:51:31 +0300 Subject: [PATCH 16/26] rpc: fixed missing read blocks (#1581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rpc: fixed missing read blocks * rpc: storage: restored old behavior * rpc: allocating 0 bytes for empty read Co-authored-by: あく --- applications/rpc/rpc_storage.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index 468e1e08e..ad6191b2f 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -320,16 +320,21 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex response->has_next = fs_operation_success && (size_left > 0); } else { - response->content.storage_read_response.has_file = false; + response->content.storage_read_response.file.data = + malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(0)); + response->content.storage_read_response.file.data->size = 0; + response->content.storage_read_response.has_file = true; response->has_next = false; fs_operation_success = true; } + + if(fs_operation_success) { + rpc_send_and_release(session, response); + } } while((size_left != 0) && fs_operation_success); } - if(fs_operation_success) { - rpc_send_and_release(session, response); - } else { + if(!fs_operation_success) { rpc_send_and_release_empty( session, request->command_id, rpc_system_storage_get_file_error(file)); } From aab8ce5e3a3ba044e8257d2741b2d51e7cf570d1 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Thu, 11 Aug 2022 18:16:47 +0300 Subject: [PATCH 17/26] Skip empty lines in favorites.txt (#1571) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/archive/helpers/archive_favorites.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c index fc0cad575..35199242e 100644 --- a/applications/archive/helpers/archive_favorites.c +++ b/applications/archive/helpers/archive_favorites.c @@ -64,7 +64,7 @@ uint16_t archive_favorites_count(void* context) { break; } if(!string_size(buffer)) { - break; + continue; // Skip empty lines } ++lines; } @@ -93,7 +93,7 @@ static bool archive_favourites_rescan() { break; } if(!string_size(buffer)) { - break; + continue; } if(string_search(buffer, "/app:") == 0) { @@ -152,7 +152,7 @@ bool archive_favorites_read(void* context) { break; } if(!string_size(buffer)) { - break; + continue; } if(string_search(buffer, "/app:") == 0) { @@ -215,7 +215,7 @@ bool archive_favorites_delete(const char* format, ...) { break; } if(!string_size(buffer)) { - break; + continue; } if(string_search(buffer, filename)) { @@ -259,7 +259,7 @@ bool archive_is_favorite(const char* format, ...) { break; } if(!string_size(buffer)) { - break; + continue; } if(!string_search(buffer, filename)) { found = true; @@ -299,7 +299,7 @@ bool archive_favorites_rename(const char* src, const char* dst) { break; } if(!string_size(buffer)) { - break; + continue; } archive_file_append( From 36b8dfe655dce5310099e33aff16aa5cfa8d7453 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 11 Aug 2022 19:21:13 +0400 Subject: [PATCH 18/26] [FL-2729] SubGhz: fix bett decoder (#1573) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: fix bett decoder * SubGhz: fix duration preamble bett protocol Co-authored-by: あく --- lib/subghz/protocols/bett.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index e32679d27..bd3b45feb 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -231,16 +231,16 @@ void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t durat switch(instance->decoder.parser_step) { case BETTDecoderStepReset: - if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 42) < - subghz_protocol_bett_const.te_delta * 21)) { + if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 44) < + (subghz_protocol_bett_const.te_delta * 15))) { //Found Preambula instance->decoder.parser_step = BETTDecoderStepCheckDuration; } break; case BETTDecoderStepSaveDuration: if(!level) { - if(duration >= ((uint32_t)subghz_protocol_bett_const.te_short * 10 + - subghz_protocol_bett_const.te_delta)) { + if(DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 44) < + (subghz_protocol_bett_const.te_delta * 15)) { instance->decoder.parser_step = BETTDecoderStepSaveDuration; if(instance->decoder.decode_count_bit == subghz_protocol_bett_const.min_count_bit_for_found) { From a5a79c5da35b9c0fa17413d6bf11ce7fe2080510 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Thu, 11 Aug 2022 18:37:23 +0300 Subject: [PATCH 19/26] [FL-2705] RPC APP fixes #1568 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/ibutton/ibutton.c | 2 + .../ibutton/scenes/ibutton_scene_rpc.c | 10 ++-- applications/infrared/infrared.c | 2 + .../infrared/scenes/infrared_scene_rpc.c | 47 ++++++++++++++----- applications/lfrfid/lfrfid_app.cpp | 6 +++ applications/lfrfid/lfrfid_app.h | 1 - .../lfrfid/scene/lfrfid_app_scene_rpc.cpp | 32 +++++-------- .../lfrfid_debug/lfrfid_debug_app.cpp | 1 + applications/nfc/nfc.c | 2 + applications/nfc/scenes/nfc_scene_rpc.c | 14 +++--- applications/subghz/scenes/subghz_scene_rpc.c | 45 +++++++++++------- applications/subghz/subghz.c | 2 + lib/app-scened-template/view_controller.hpp | 5 +- 13 files changed, 105 insertions(+), 64 deletions(-) diff --git a/applications/ibutton/ibutton.c b/applications/ibutton/ibutton.c index b30a4c61f..7ee1110e1 100644 --- a/applications/ibutton/ibutton.c +++ b/applications/ibutton/ibutton.c @@ -87,6 +87,8 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) if(event == RpcAppEventSessionClose) { view_dispatcher_send_custom_event( ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); + rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); + ibutton->rpc_ctx = NULL; } else if(event == RpcAppEventAppExit) { view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); } else if(event == RpcAppEventLoadFile) { diff --git a/applications/ibutton/scenes/ibutton_scene_rpc.c b/applications/ibutton/scenes/ibutton_scene_rpc.c index a3f5eeee4..0755c8ff8 100644 --- a/applications/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/ibutton/scenes/ibutton_scene_rpc.c @@ -29,7 +29,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.event == iButtonCustomEventRpcLoad) { const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); bool result = false; - if(arg) { + if(arg && (string_empty_p(ibutton->file_path))) { string_set_str(ibutton->file_path, arg); if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); @@ -51,17 +51,17 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { string_clear(key_name); result = true; + } else { + string_reset(ibutton->file_path); } } rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); } else if(event.event == iButtonCustomEventRpcExit) { rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); - ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); + scene_manager_stop(ibutton->scene_manager); view_dispatcher_stop(ibutton->view_dispatcher); } else if(event.event == iButtonCustomEventRpcSessionClose) { - rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); - ibutton->rpc_ctx = NULL; - ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); + scene_manager_stop(ibutton->scene_manager); view_dispatcher_stop(ibutton->view_dispatcher); } } diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c index aef14f9b8..3b4da647f 100644 --- a/applications/infrared/infrared.c +++ b/applications/infrared/infrared.c @@ -46,6 +46,8 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context if(event == RpcAppEventSessionClose) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); + rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); + infrared->rpc_ctx = NULL; } else if(event == RpcAppEventAppExit) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); diff --git a/applications/infrared/scenes/infrared_scene_rpc.c b/applications/infrared/scenes/infrared_scene_rpc.c index bc9c8652f..cb5535fed 100644 --- a/applications/infrared/scenes/infrared_scene_rpc.c +++ b/applications/infrared/scenes/infrared_scene_rpc.c @@ -1,20 +1,28 @@ #include "../infrared_i.h" #include "gui/canvas.h" +typedef enum { + InfraredRpcStateIdle, + InfraredRpcStateLoaded, + InfraredRpcStateSending, +} InfraredRpcState; + void infrared_scene_rpc_on_enter(void* context) { Infrared* infrared = context; Popup* popup = infrared->popup; - popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom); - popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); - popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon + popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); popup_set_context(popup, context); popup_set_callback(popup, infrared_popup_closed_callback); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); + scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle); + notification_message(infrared->notifications, &sequence_display_backlight_on); } @@ -24,6 +32,8 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { consumed = true; + InfraredRpcState state = + scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc); if(event.event == InfraredCustomEventTypeBackPressed) { view_dispatcher_stop(infrared->view_dispatcher); } else if(event.event == InfraredCustomEventTypePopupClosed) { @@ -31,39 +41,51 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == InfraredCustomEventTypeRpcLoad) { bool result = false; const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); - if(arg) { + if(arg && (state == InfraredRpcStateIdle)) { string_set_str(infrared->file_path, arg); result = infrared_remote_load(infrared->remote, infrared->file_path); infrared_worker_tx_set_get_signal_callback( infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); + if(result) { + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); + } } const char* remote_name = infrared_remote_get_name(infrared->remote); infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); popup_set_text( - infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop); + infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop); rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); } else if(event.event == InfraredCustomEventTypeRpcButtonPress) { bool result = false; const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); - if(arg) { + if(arg && (state == InfraredRpcStateLoaded)) { size_t button_index = 0; if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { infrared_tx_start_button_index(infrared, button_index); result = true; + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending); } } rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { - infrared_tx_stop(infrared); - rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true); + bool result = false; + if(state == InfraredRpcStateSending) { + infrared_tx_stop(infrared); + result = true; + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); + } + rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); } else if(event.event == InfraredCustomEventTypeRpcExit) { + scene_manager_stop(infrared->scene_manager); view_dispatcher_stop(infrared->view_dispatcher); rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); } else if(event.event == InfraredCustomEventTypeRpcSessionClose) { - rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); - infrared->rpc_ctx = NULL; + scene_manager_stop(infrared->scene_manager); view_dispatcher_stop(infrared->view_dispatcher); } } @@ -72,6 +94,9 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { void infrared_scene_rpc_on_exit(void* context) { Infrared* infrared = context; - infrared_tx_stop(infrared); + if(scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc) == + InfraredRpcStateSending) { + infrared_tx_stop(infrared); + } popup_reset(infrared->popup); } diff --git a/applications/lfrfid/lfrfid_app.cpp b/applications/lfrfid/lfrfid_app.cpp index 5b762ae1d..f1a575de5 100644 --- a/applications/lfrfid/lfrfid_app.cpp +++ b/applications/lfrfid/lfrfid_app.cpp @@ -56,6 +56,9 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { LfRfidApp::Event event; event.type = LfRfidApp::EventType::RpcSessionClose; app->view_controller.send_event(&event); + // Detach RPC + rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); + app->rpc_ctx = NULL; } else if(rpc_event == RpcAppEventAppExit) { LfRfidApp::Event event; event.type = LfRfidApp::EventType::Exit; @@ -80,16 +83,19 @@ void LfRfidApp::run(void* _args) { rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr; rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this); rpc_system_app_send_started(rpc_ctx); + view_controller.attach_to_gui(ViewDispatcherTypeDesktop); scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); scene_controller.process(100, SceneType::Rpc); } else { string_set_str(file_path, args); load_key_data(file_path, &worker.key, true); + view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); scene_controller.process(100, SceneType::Emulate); } } else { + view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm()); diff --git a/applications/lfrfid/lfrfid_app.h b/applications/lfrfid/lfrfid_app.h index b0d4c5898..db022c9aa 100644 --- a/applications/lfrfid/lfrfid_app.h +++ b/applications/lfrfid/lfrfid_app.h @@ -101,5 +101,4 @@ public: bool save_key_data(string_t path, RfidKey* key); void make_app_folder(); - //bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context); }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp index 43b236286..54a57c9a2 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp @@ -6,9 +6,9 @@ void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) { auto popup = app->view_controller.get(); - popup->set_header("LF RFID", 89, 30, AlignCenter, AlignTop); - popup->set_text("RPC mode", 89, 43, AlignCenter, AlignTop); - popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); + popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom); + popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop); + popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61); app->view_controller.switch_to(); @@ -27,33 +27,25 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { app->view_controller.send_event(&view_event); rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { - // Detach RPC - rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); - app->rpc_ctx = NULL; - consumed = true; LfRfidApp::Event view_event; view_event.type = LfRfidApp::EventType::Back; app->view_controller.send_event(&view_event); - } else if(event->type == LfRfidApp::EventType::EmulateStart) { - auto popup = app->view_controller.get(); - consumed = true; - emulating = true; - - app->text_store.set("emulating\n%s", app->worker.key.get_name()); - popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop); - - notification_message(app->notification, &sequence_blink_start_magenta); } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { const char* arg = rpc_system_app_get_data(app->rpc_ctx); + consumed = true; bool result = false; - if(arg) { + if(arg && !emulating) { string_set_str(app->file_path, arg); if(app->load_key_data(app->file_path, &(app->worker.key), false)) { - LfRfidApp::Event event; - event.type = LfRfidApp::EventType::EmulateStart; - app->view_controller.send_event(&event); app->worker.start_emulate(); + emulating = true; + + auto popup = app->view_controller.get(); + app->text_store.set("emulating\n%s", app->worker.key.get_name()); + popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); + + notification_message(app->notification, &sequence_blink_start_magenta); result = true; } } diff --git a/applications/lfrfid_debug/lfrfid_debug_app.cpp b/applications/lfrfid_debug/lfrfid_debug_app.cpp index 9cd9dcad8..ef970e361 100644 --- a/applications/lfrfid_debug/lfrfid_debug_app.cpp +++ b/applications/lfrfid_debug/lfrfid_debug_app.cpp @@ -10,6 +10,7 @@ LfRfidDebugApp::~LfRfidDebugApp() { } void LfRfidDebugApp::run() { + view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart()); scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune()); scene_controller.process(100); diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index 9d32e8713..6b8843db2 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -21,6 +21,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { if(event == RpcAppEventSessionClose) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); + rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); + nfc->rpc_ctx = NULL; } else if(event == RpcAppEventAppExit) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } else if(event == RpcAppEventLoadFile) { diff --git a/applications/nfc/scenes/nfc_scene_rpc.c b/applications/nfc/scenes/nfc_scene_rpc.c index 94beccc6b..7a9eb4503 100644 --- a/applications/nfc/scenes/nfc_scene_rpc.c +++ b/applications/nfc/scenes/nfc_scene_rpc.c @@ -4,10 +4,10 @@ void nfc_scene_rpc_on_enter(void* context) { Nfc* nfc = context; Popup* popup = nfc->popup; - popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom); - popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); - popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon + popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); @@ -31,13 +31,11 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { consumed = true; if(event.event == NfcCustomEventViewExit) { rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); + scene_manager_stop(nfc->scene_manager); view_dispatcher_stop(nfc->view_dispatcher); - nfc_blink_stop(nfc); } else if(event.event == NfcCustomEventRpcSessionClose) { - rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); - nfc->rpc_ctx = NULL; + scene_manager_stop(nfc->scene_manager); view_dispatcher_stop(nfc->view_dispatcher); - nfc_blink_stop(nfc); } else if(event.event == NfcCustomEventRpcLoad) { bool result = false; const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); @@ -66,7 +64,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { nfc_blink_start(nfc); nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); - popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); + popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop); } } diff --git a/applications/subghz/scenes/subghz_scene_rpc.c b/applications/subghz/scenes/subghz_scene_rpc.c index c6f7df268..652499d05 100644 --- a/applications/subghz/scenes/subghz_scene_rpc.c +++ b/applications/subghz/scenes/subghz_scene_rpc.c @@ -1,16 +1,23 @@ #include "../subghz_i.h" +typedef enum { + SubGhzRpcStateIdle, + SubGhzRpcStateLoaded, +} SubGhzRpcState; + void subghz_scene_rpc_on_enter(void* context) { SubGhz* subghz = context; Popup* popup = subghz->popup; - popup_set_header(popup, "Sub-GHz", 82, 28, AlignCenter, AlignBottom); - popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + popup_set_header(popup, "Sub-GHz", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); - popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon + popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); + scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + notification_message(subghz->notifications, &sequence_display_backlight_on); } @@ -18,28 +25,21 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; Popup* popup = subghz->popup; bool consumed = false; + SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == SubGhzCustomEventSceneExit) { - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } + scene_manager_stop(subghz->scene_manager); view_dispatcher_stop(subghz->view_dispatcher); rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventAppExit, true); } else if(event.event == SubGhzCustomEventSceneRpcSessionClose) { - rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); - subghz->rpc_ctx = NULL; - subghz_blink_stop(subghz); - if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { - subghz_tx_stop(subghz); - subghz_sleep(subghz); - } - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { + if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) && + (state == SubGhzRpcStateLoaded)) { subghz_blink_start(subghz); result = subghz_tx_start(subghz, subghz->txrx->fff_data); result = true; @@ -57,8 +57,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; const char* arg = rpc_system_app_get_data(subghz->rpc_ctx); - if(arg) { + if(arg && (state == SubGhzRpcStateIdle)) { if(subghz_key_load(subghz, arg, false)) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); string_set_str(subghz->file_path, arg); result = true; string_t file_name; @@ -70,7 +72,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { SUBGHZ_MAX_LEN_NAME, "loaded\n%s", string_get_cstr(file_name)); - popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop); + popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop); string_clear(file_name); } @@ -83,6 +85,13 @@ 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); + subghz_blink_stop(subghz); + } + Popup* popup = subghz->popup; popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 3770d52c1..4eb4bbd68 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -32,6 +32,8 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) if(event == RpcAppEventSessionClose) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcSessionClose); + rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); + subghz->rpc_ctx = NULL; } else if(event == RpcAppEventAppExit) { view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); } else if(event == RpcAppEventLoadFile) { diff --git a/lib/app-scened-template/view_controller.hpp b/lib/app-scened-template/view_controller.hpp index d08751c58..15028f533 100644 --- a/lib/app-scened-template/view_controller.hpp +++ b/lib/app-scened-template/view_controller.hpp @@ -26,7 +26,6 @@ public: 0)...); gui = static_cast(furi_record_open("gui")); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); }; ~ViewController() { @@ -96,6 +95,10 @@ public: furi_check(result == FuriStatusOk); } + void attach_to_gui(ViewDispatcherType type) { + view_dispatcher_attach_to_gui(view_dispatcher, gui, type); + } + private: /** * @brief ViewModulesHolder From e0b184c057db27e3fa873b9a05bf3e5a3820dff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 12 Aug 2022 01:10:50 +0900 Subject: [PATCH 20/26] Scripts: add new region to otp generator (#1582) --- scripts/otp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/otp.py b/scripts/otp.py index 7b2378d12..48056fd2a 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -24,6 +24,7 @@ OTP_REGIONS = { "eu_ru": 0x01, "us_ca_au": 0x02, "jp": 0x03, + "world": 0x04, } OTP_DISPLAYS = { From 1db7632041687a546ffbdc7ddfc75aaceb48bc09 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Fri, 12 Aug 2022 03:01:25 -0600 Subject: [PATCH 21/26] fbt: clear PYTHONPATH in env setup (#1585) --- scripts/toolchain/fbtenv.cmd | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 471ce835c..aac2a3309 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -31,6 +31,7 @@ if not "%REAL_TOOLCHAIN_VERSION%" == "%FLIPPER_TOOLCHAIN_VERSION%" ( set "HOME=%USERPROFILE%" set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" +set "PYTHONPATH=" set "PATH=%FBT_TOOLCHAIN_ROOT%\python;%FBT_TOOLCHAIN_ROOT%\bin;%FBT_TOOLCHAIN_ROOT%\protoc\bin;%FBT_TOOLCHAIN_ROOT%\openocd\bin;%PATH%" set "PROMPT=(fbt) %PROMPT%" From 6ee2c15854c3f29490697cdf85388ae5754eeba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 12 Aug 2022 19:19:29 +0900 Subject: [PATCH 22/26] FuriHal,About,Desktop: show provisioned region (#1589) Co-authored-by: hedger --- applications/about/about.c | 4 +++- applications/desktop/views/desktop_view_debug.c | 3 ++- firmware/targets/f7/furi_hal/furi_hal_version.c | 2 ++ firmware/targets/furi_hal_include/furi_hal_version.h | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/applications/about/about.c b/applications/about/about.c index f785c2e40..6b4489f0a 100644 --- a/applications/about/about.c +++ b/applications/about/about.c @@ -5,6 +5,7 @@ #include #include #include +#include #include typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); @@ -83,12 +84,13 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* string_cat_printf( buffer, - "%d.F%dB%dC%d %s %s\n", + "%d.F%dB%dC%d %s:%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(), + furi_hal_region_get_name(), my_name ? my_name : "Unknown"); string_cat_printf(buffer, "Serial Number:\n"); diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/desktop/views/desktop_view_debug.c index e26411932..69c82bdbe 100644 --- a/applications/desktop/views/desktop_view_debug.c +++ b/applications/desktop/views/desktop_view_debug.c @@ -36,12 +36,13 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%d.F%dB%dC%d %s %s", + "%d.F%dB%dC%d %s:%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(), + furi_hal_region_get_name(), my_name ? my_name : "Unknown"); canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 7abee281f..0d87c8073 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -262,6 +262,8 @@ const char* furi_hal_version_get_hw_region_name() { return "R02"; case FuriHalVersionRegionJp: return "R03"; + case FuriHalVersionRegionWorld: + return "R04"; } return "R??"; } diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index 500e0d813..720fdfd17 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -41,6 +41,7 @@ typedef enum { FuriHalVersionRegionEuRu = 0x01, FuriHalVersionRegionUsCaAu = 0x02, FuriHalVersionRegionJp = 0x03, + FuriHalVersionRegionWorld = 0x04, } FuriHalVersionRegion; /** Device Display */ From c846bca280425ee463bc132f507c8f3ddd78ee29 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 12 Aug 2022 16:40:28 +0300 Subject: [PATCH 23/26] FuriHal: do not enable LSECSS if BORRST is active (#1590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f7/furi_hal/furi_hal_clock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index 09efe76dd..a7c9b4d03 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -75,7 +75,10 @@ void furi_hal_clock_init() { 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); LL_RCC_EnableIT_LSECSS(); - LL_RCC_LSE_EnableCSS(); + /* ES0394, extended case of 2.2.2 */ + if(!LL_RCC_IsActiveFlag_BORRST()) { + LL_RCC_LSE_EnableCSS(); + } /* Main PLL configuration and activation */ LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 8, LL_RCC_PLLR_DIV_2); From 1655366ef49a111af697aa9f10cc6fa6c0d5f55d Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 12 Aug 2022 16:50:04 +0300 Subject: [PATCH 24/26] [FL-2728] Fix Null Pointer Dereference errors in IR #1583 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/infrared/infrared.c | 21 ++++++++- applications/infrared/infrared_i.h | 2 + .../scenes/infrared_scene_learn_success.c | 43 ++++--------------- .../infrared/scenes/infrared_scene_remote.c | 37 +++++++++------- .../infrared/scenes/infrared_scene_rpc.c | 2 - 5 files changed, 51 insertions(+), 54 deletions(-) diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c index 3b4da647f..60809e787 100644 --- a/applications/infrared/infrared.c +++ b/applications/infrared/infrared.c @@ -295,6 +295,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) { } void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { + if(infrared->app_state.is_transmitting) { + FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active"); + return; + } else { + infrared->app_state.is_transmitting = true; + } + if(infrared_signal_is_raw(signal)) { InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); @@ -304,8 +311,11 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { } DOLPHIN_DEED(DolphinDeedIrSend); - infrared_worker_tx_start(infrared->worker); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); + + infrared_worker_tx_set_get_signal_callback( + infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); + infrared_worker_tx_start(infrared->worker); } void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { @@ -324,7 +334,16 @@ void infrared_tx_start_received(Infrared* infrared) { } void infrared_tx_stop(Infrared* infrared) { + if(!infrared->app_state.is_transmitting) { + FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped"); + return; + } else { + infrared->app_state.is_transmitting = false; + } + infrared_worker_tx_stop(infrared->worker); + infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); } diff --git a/applications/infrared/infrared_i.h b/applications/infrared/infrared_i.h index 4e9c79d51..952152587 100644 --- a/applications/infrared/infrared_i.h +++ b/applications/infrared/infrared_i.h @@ -43,6 +43,7 @@ #define INFRARED_APP_EXTENSION ".ir" #define INFRARED_DEFAULT_REMOTE_NAME "Remote" +#define INFRARED_LOG_TAG "InfraredApp" typedef enum { InfraredButtonIndexNone = -1, @@ -63,6 +64,7 @@ typedef enum { typedef struct { bool is_learning_new_remote; bool is_debug_enabled; + bool is_transmitting; InfraredEditTarget edit_target : 8; InfraredEditMode edit_mode : 8; int32_t current_button_index; diff --git a/applications/infrared/scenes/infrared_scene_learn_success.c b/applications/infrared/scenes/infrared_scene_learn_success.c index 49e2f45f0..9368c8499 100644 --- a/applications/infrared/scenes/infrared_scene_learn_success.c +++ b/applications/infrared/scenes/infrared_scene_learn_success.c @@ -2,11 +2,6 @@ #include -typedef enum { - InfraredSceneLearnSuccessStateIdle = 0, - InfraredSceneLearnSuccessStateSending = 1, -} InfraredSceneLearnSuccessState; - static void infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { Infrared* infrared = context; @@ -21,9 +16,6 @@ void infrared_scene_learn_success_on_enter(void* context) { DOLPHIN_DEED(DolphinDeedIrLearnSuccess); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); - infrared_worker_tx_set_get_signal_callback( - infrared->worker, infrared_worker_tx_get_signal_steady_callback, context); - if(infrared_signal_is_raw(signal)) { InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); @@ -63,57 +55,42 @@ void infrared_scene_learn_success_on_enter(void* context) { dialog_ex_set_context(dialog_ex, context); dialog_ex_enable_extended_events(dialog_ex); - scene_manager_set_scene_state( - infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); } bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { Infrared* infrared = context; SceneManager* scene_manager = infrared->scene_manager; - uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess); + const bool is_transmitter_idle = !infrared->app_state.is_transmitting; bool consumed = false; if(event.type == SceneManagerEventTypeTick) { - if(scene_state == InfraredSceneLearnSuccessStateIdle) { + if(is_transmitter_idle) { infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); } consumed = true; } else if(event.type == SceneManagerEventTypeBack) { - if(scene_state == InfraredSceneLearnSuccessStateIdle) { + if(is_transmitter_idle) { scene_manager_next_scene(scene_manager, InfraredSceneAskBack); } consumed = true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultLeft) { - if(scene_state == InfraredSceneLearnSuccessStateIdle) { + if(is_transmitter_idle) { scene_manager_next_scene(scene_manager, InfraredSceneAskRetry); } consumed = true; } else if(event.event == DialogExResultRight) { - if(scene_state == InfraredSceneLearnSuccessStateIdle) { + if(is_transmitter_idle) { scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); } consumed = true; } else if(event.event == DialogExPressCenter) { - if(scene_state == InfraredSceneLearnSuccessStateIdle) { - scene_manager_set_scene_state( - scene_manager, - InfraredSceneLearnSuccess, - InfraredSceneLearnSuccessStateSending); - infrared_tx_start_received(infrared); - infrared_play_notification_message( - infrared, InfraredNotificationMessageBlinkStartSend); - } + infrared_tx_start_received(infrared); consumed = true; } else if(event.event == DialogExReleaseCenter) { - if(scene_state == InfraredSceneLearnSuccessStateSending) { - scene_manager_set_scene_state( - scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); - infrared_tx_stop(infrared); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); - infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); - } + infrared_tx_stop(infrared); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); consumed = true; } } @@ -123,9 +100,5 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even void infrared_scene_learn_success_on_exit(void* context) { Infrared* infrared = context; - InfraredWorker* worker = infrared->worker; dialog_ex_reset(infrared->dialog_ex); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); - infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); - infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL); } diff --git a/applications/infrared/scenes/infrared_scene_remote.c b/applications/infrared/scenes/infrared_scene_remote.c index bcac58819..c1f5b6627 100644 --- a/applications/infrared/scenes/infrared_scene_remote.c +++ b/applications/infrared/scenes/infrared_scene_remote.c @@ -31,9 +31,6 @@ void infrared_scene_remote_on_enter(void* context) { ButtonMenu* button_menu = infrared->button_menu; SceneManager* scene_manager = infrared->scene_manager; - infrared_worker_tx_set_get_signal_callback( - infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); - size_t button_count = infrared_remote_get_button_count(remote); for(size_t i = 0; i < button_count; ++i) { InfraredRemoteButton* button = infrared_remote_get_button(remote, i); @@ -73,12 +70,17 @@ void infrared_scene_remote_on_enter(void* context) { bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { Infrared* infrared = context; SceneManager* scene_manager = infrared->scene_manager; + const bool is_transmitter_idle = !infrared->app_state.is_transmitting; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { - const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; - consumed = scene_manager_search_and_switch_to_previous_scene_one_of( - scene_manager, possible_scenes, COUNT_OF(possible_scenes)); + if(is_transmitter_idle) { + const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; + consumed = scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, COUNT_OF(possible_scenes)); + } else { + consumed = true; + } } else if(event.type == SceneManagerEventTypeCustom) { const uint16_t custom_type = infrared_custom_event_get_type(event.event); const int16_t button_index = infrared_custom_event_get_value(event.event); @@ -92,14 +94,19 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(custom_type == InfraredCustomEventTypeMenuSelected) { furi_assert(button_index < 0); - scene_manager_set_scene_state( - scene_manager, InfraredSceneRemote, (unsigned)button_index); - if(button_index == ButtonIndexPlus) { - infrared->app_state.is_learning_new_remote = false; - scene_manager_next_scene(scene_manager, InfraredSceneLearn); - consumed = true; - } else if(button_index == ButtonIndexEdit) { - scene_manager_next_scene(scene_manager, InfraredSceneEdit); + if(is_transmitter_idle) { + scene_manager_set_scene_state( + scene_manager, InfraredSceneRemote, (unsigned)button_index); + if(button_index == ButtonIndexPlus) { + infrared->app_state.is_learning_new_remote = false; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(button_index == ButtonIndexEdit) { + scene_manager_next_scene(scene_manager, InfraredSceneEdit); + consumed = true; + } + + } else { consumed = true; } } @@ -110,7 +117,5 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { void infrared_scene_remote_on_exit(void* context) { Infrared* infrared = context; - infrared_tx_stop(infrared); - infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); button_menu_reset(infrared->button_menu); } diff --git a/applications/infrared/scenes/infrared_scene_rpc.c b/applications/infrared/scenes/infrared_scene_rpc.c index cb5535fed..ca7bbd8df 100644 --- a/applications/infrared/scenes/infrared_scene_rpc.c +++ b/applications/infrared/scenes/infrared_scene_rpc.c @@ -44,8 +44,6 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(arg && (state == InfraredRpcStateIdle)) { string_set_str(infrared->file_path, arg); result = infrared_remote_load(infrared->remote, infrared->file_path); - infrared_worker_tx_set_get_signal_callback( - infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); if(result) { scene_manager_set_scene_state( infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); From 9e452d2b26acfff2e12289f925c2b609bd2a6544 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 12 Aug 2022 17:40:26 +0300 Subject: [PATCH 25/26] [FL-2735] IR green LED fix (#1591) * Fix incorrect LED behaviour * Turn green LED off before blinking --- applications/infrared/scenes/infrared_scene_learn_success.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/infrared/scenes/infrared_scene_learn_success.c b/applications/infrared/scenes/infrared_scene_learn_success.c index 9368c8499..466627144 100644 --- a/applications/infrared/scenes/infrared_scene_learn_success.c +++ b/applications/infrared/scenes/infrared_scene_learn_success.c @@ -86,11 +86,11 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even } consumed = true; } else if(event.event == DialogExPressCenter) { + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); infrared_tx_start_received(infrared); consumed = true; } else if(event.event == DialogExReleaseCenter) { infrared_tx_stop(infrared); - infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); consumed = true; } } @@ -101,4 +101,5 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even void infrared_scene_learn_success_on_exit(void* context) { Infrared* infrared = context; dialog_ex_reset(infrared->dialog_ex); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); } From e1ffb4ac4d7380ed289ac75af0314e4fdcfcbf6b Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 13 Aug 2022 01:17:11 +0300 Subject: [PATCH 26/26] fbt: support for LOADER_AUTOSTART; post-build size stats (#1594) * fbt: restored LOADER_AUTOSTART support * scripts: added fwsize.py wrapper for size command; fbt: changed size post-build stats to fwsize.py call * fbt: removed size wrapper * fbt: added stats for binary flash size in pages * fbt: hint on build options details * scripts: fixed fwsize.py for *nix --- applications/applications.h | 2 ++ applications/loader/loader.c | 6 ++-- fbt_options.py | 5 +++ firmware.scons | 12 +++++-- scripts/fwsize.py | 52 +++++++++++++++++++++++++++++++ site_scons/commandline.scons | 6 ++++ site_scons/fbt/appmanifest.py | 9 ++++-- site_scons/site_tools/crosscc.py | 4 +-- site_scons/site_tools/fbt_apps.py | 2 +- site_scons/site_tools/size.py | 24 -------------- 10 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 scripts/fwsize.py delete mode 100644 site_scons/site_tools/size.py diff --git a/applications/applications.h b/applications/applications.h index bebe438ab..012e80ddb 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -18,6 +18,8 @@ typedef struct { typedef void (*FlipperOnStartHook)(void); +extern const char* FLIPPER_AUTORUN_APP_NAME; + /* Services list * Spawned on startup */ diff --git a/applications/loader/loader.c b/applications/loader/loader.c index 3f4e876f3..9ece7f271 100644 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -466,9 +466,9 @@ int32_t loader_srv(void* p) { furi_record_create(RECORD_LOADER, loader_instance); -#ifdef LOADER_AUTOSTART - loader_start(loader_instance, LOADER_AUTOSTART, NULL); -#endif + if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { + loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL); + } while(1) { uint32_t flags = diff --git a/fbt_options.py b/fbt_options.py index 7276f579e..b154d26aa 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -1,5 +1,7 @@ import posixpath +# For more details on these options, run 'fbt -h' + # Default hardware target TARGET_HW = 7 @@ -59,6 +61,9 @@ SVD_FILE = "debug/STM32WB55_CM4.svd" # Look for blackmagic probe on serial ports and local network BLACKMAGIC = "auto" +# Application to start on boot +LOADER_AUTOSTART = "" + FIRMWARE_APPS = { "default": [ "crypto_start", diff --git a/firmware.scons b/firmware.scons index 064e0ddab..863b35fca 100644 --- a/firmware.scons +++ b/firmware.scons @@ -139,7 +139,7 @@ fwenv.AppendUnique( # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes apps_c = fwenv.ApplicationsC( "applications/applications.c", - Value(fwenv["APPS"]), + [Value(fwenv["APPS"]), Value(fwenv["LOADER_AUTOSTART"])], ) # Adding dependency on manifest files so apps.c is rebuilt when any manifest is changed fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", "#/applications")) @@ -210,11 +210,19 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program( Depends(fwelf, lib_targets) # Output extra details after building firmware AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) -AddPostAction(fwelf, Action("@$SIZECOM")) +AddPostAction( + fwelf, + Action('${PYTHON3} "${ROOT_DIR}/scripts/fwsize.py" elf ${TARGET}', "Firmware size"), +) # Produce extra firmware files fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") +AddPostAction( + fwbin, + Action('@${PYTHON3} "${ROOT_DIR}/scripts/fwsize.py" bin ${TARGET}'), +) + fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) diff --git a/scripts/fwsize.py b/scripts/fwsize.py new file mode 100644 index 000000000..b381f6e9a --- /dev/null +++ b/scripts/fwsize.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +from flipper.app import App +import subprocess +import os +import math + + +class Main(App): + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + self.parser_elfsize = self.subparsers.add_parser("elf", help="Dump elf stats") + self.parser_elfsize.add_argument("elfname", action="store") + self.parser_elfsize.set_defaults(func=self.process_elf) + + self.parser_binsize = self.subparsers.add_parser("bin", help="Dump bin stats") + self.parser_binsize.add_argument("binname", action="store") + self.parser_binsize.set_defaults(func=self.process_bin) + + def process_elf(self): + all_sizes = subprocess.check_output( + ["arm-none-eabi-size", "-A", self.args.elfname], shell=False + ) + all_sizes = all_sizes.splitlines() + + sections_to_keep = (".text", ".rodata", ".data", ".bss", ".free_flash") + for line in all_sizes: + line = line.decode("utf-8") + parts = line.split() + if len(parts) != 3: + continue + section, size, _ = parts + if section not in sections_to_keep: + continue + print(f"{section:<11} {size:>8} ({(int(size)/1024):6.2f} K)") + + return 0 + + def process_bin(self): + PAGE_SIZE = 4096 + binsize = os.path.getsize(self.args.binname) + pages = math.ceil(binsize / PAGE_SIZE) + last_page_state = (binsize % PAGE_SIZE) * 100 / PAGE_SIZE + print( + f"{os.path.basename(self.args.binname):<11}: {pages:>4} flash pages (last page {last_page_state:.02f}% full)" + ) + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 5a7a0dd2d..4c96268b6 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -174,6 +174,12 @@ vars.Add( default="update_default", ) +vars.Add( + "LOADER_AUTOSTART", + help="Application name to automatically run on Flipper boot", + default="", +) + vars.Add( "FIRMWARE_APPS", diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py index 990bd5b3b..aacf248ec 100644 --- a/site_scons/fbt/appmanifest.py +++ b/site_scons/fbt/appmanifest.py @@ -200,8 +200,9 @@ class ApplicationsCGenerator: FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), } - def __init__(self, buildset: AppBuildset): + def __init__(self, buildset: AppBuildset, autorun_app: str = ""): self.buildset = buildset + self.autorun = autorun_app def get_app_ep_forward(self, app: FlipperApplication): if app.apptype == FlipperAppType.STARTUP: @@ -219,7 +220,11 @@ class ApplicationsCGenerator: .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" def generate(self): - contents = ['#include "applications.h"', "#include "] + contents = [ + '#include "applications.h"', + "#include ", + f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', + ] for apptype in self.APP_TYPE_MAP: contents.extend( map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index dbedf5c07..aacda58c6 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -7,7 +7,6 @@ from SCons.Tool import gnulink import strip import gdb import objdump -import size from SCons.Action import _subproc import subprocess @@ -38,7 +37,7 @@ def _get_tool_version(env, tool): def generate(env, **kw): - for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump, size): + for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump): orig_tool.generate(env) env.SetDefault( TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"), @@ -57,7 +56,6 @@ def generate(env, **kw): "GDB", "GDBPY", "OBJDUMP", - "SIZE", ], ) # Call CC to check version diff --git a/site_scons/site_tools/fbt_apps.py b/site_scons/site_tools/fbt_apps.py index 2cd63b70b..3dc35049b 100644 --- a/site_scons/site_tools/fbt_apps.py +++ b/site_scons/site_tools/fbt_apps.py @@ -51,7 +51,7 @@ def DumpApplicationConfig(target, source, env): def build_apps_c(target, source, env): target_file_name = target[0].path - gen = ApplicationsCGenerator(env["APPBUILD"]) + gen = ApplicationsCGenerator(env["APPBUILD"], env.subst("$LOADER_AUTOSTART")) with open(target_file_name, "w") as file: file.write(gen.generate()) diff --git a/site_scons/site_tools/size.py b/site_scons/site_tools/size.py deleted file mode 100644 index 56d4f3c9e..000000000 --- a/site_scons/site_tools/size.py +++ /dev/null @@ -1,24 +0,0 @@ -from SCons.Builder import Builder -from SCons.Action import Action - - -def generate(env): - env.SetDefault( - SIZE="size", - SIZEFLAGS=[], - SIZECOM="$SIZE $SIZEFLAGS $TARGETS", - ) - env.Append( - BUILDERS={ - "ELFSize": Builder( - action=Action( - "${SIZECOM}", - "${SIZECOMSTR}", - ), - ), - } - ) - - -def exists(env): - return True