diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml index 571e88c4..39a7eabe 100644 --- a/.github/workflows/lint_c.yml +++ b/.github/workflows/lint_c.yml @@ -1,13 +1,6 @@ name: 'Lint C/C++ with clang-format' -on: - push: - paths: - - '**.h' - - '**.c' - - '**.hpp' - - '**.cpp' - pull_request: +on: pull_request env: TARGETS: f6 diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index adff291e..4a70d48b 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -1,10 +1,6 @@ name: 'Python Lint' -on: - push: - paths: - - '**.py' - pull_request: +on: pull_request jobs: lint_python: diff --git a/applications/archive/archive_i.h b/applications/archive/archive_i.h index 38991f7b..006a7bbf 100644 --- a/applications/archive/archive_i.h +++ b/applications/archive/archive_i.h @@ -35,7 +35,7 @@ static const char* flipper_app_name[] = { static const char* known_ext[] = { [ArchiveFileTypeIButton] = ".ibtn", [ArchiveFileTypeNFC] = ".nfc", - [ArchiveFileTypeSubOne] = ".sub1", + [ArchiveFileTypeSubOne] = ".sub", [ArchiveFileTypeLFRFID] = ".rfid", [ArchiveFileTypeIrda] = ".ir", }; @@ -44,7 +44,7 @@ static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/any/favorites", [ArchiveTabIButton] = "/any/ibutton", [ArchiveTabNFC] = "/any/nfc", - [ArchiveTabSubOne] = "/any/subone", + [ArchiveTabSubOne] = "/any/subghz/saved", [ArchiveTabLFRFID] = "/any/lfrfid", [ArchiveTabIrda] = "/any/irda", [ArchiveTabBrowser] = "/any", diff --git a/applications/archive/archive_views.c b/applications/archive/archive_views.c index bd3286f1..e2d52241 100644 --- a/applications/archive/archive_views.c +++ b/applications/archive/archive_views.c @@ -4,7 +4,7 @@ static const char* ArchiveTabNames[] = { [ArchiveTabFavorites] = "Favorites", [ArchiveTabIButton] = "iButton", [ArchiveTabNFC] = "NFC", - [ArchiveTabSubOne] = "SubOne", + [ArchiveTabSubOne] = "SubGhz", [ArchiveTabLFRFID] = "RFID LF", [ArchiveTabIrda] = "Infrared", [ArchiveTabBrowser] = "Browser"}; diff --git a/applications/subghz/scenes/subghz_scene.c b/applications/subghz/scenes/subghz_scene.c new file mode 100644 index 00000000..be84949d --- /dev/null +++ b/applications/subghz/scenes/subghz_scene.c @@ -0,0 +1,30 @@ +#include "subghz_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const subghz_on_enter_handlers[])(void*) = { +#include "subghz_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const subghz_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "subghz_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const subghz_on_exit_handlers[])(void* context) = { +#include "subghz_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers subghz_scene_handlers = { + .on_enter_handlers = subghz_on_enter_handlers, + .on_event_handlers = subghz_on_event_handlers, + .on_exit_handlers = subghz_on_exit_handlers, + .scene_num = SubGhzSceneNum, +}; diff --git a/applications/subghz/scenes/subghz_scene.h b/applications/subghz/scenes/subghz_scene.h new file mode 100644 index 00000000..2b667852 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubGhzScene##id, +typedef enum { +#include "subghz_scene_config.h" + SubGhzSceneNum, +} SubGhzScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subghz_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subghz_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "subghz_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "subghz_scene_config.h" +#undef ADD_SCENE diff --git a/applications/subghz/scenes/subghz_scene_analyze.c b/applications/subghz/scenes/subghz_scene_analyze.c new file mode 100644 index 00000000..e5985893 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_analyze.c @@ -0,0 +1,15 @@ +#include "../subghz_i.h" + +const void subghz_scene_analyze_on_enter(void* context) { + SubGhz* subghz = context; + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewAnalyze); +} + +const bool subghz_scene_analyze_on_event(void* context, SceneManagerEvent event) { + // SubGhz* subghz = context; + return false; +} + +const void subghz_scene_analyze_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h new file mode 100644 index 00000000..aa2ddd6a --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -0,0 +1,12 @@ +ADD_SCENE(subghz, start, Start) +ADD_SCENE(subghz, analyze, Analyze) +ADD_SCENE(subghz, read, Read) +ADD_SCENE(subghz, receiver, Receiver) +ADD_SCENE(subghz, save_name, SaveName) +ADD_SCENE(subghz, save_success, SaveSuccess) +ADD_SCENE(subghz, saved, Saved) +ADD_SCENE(subghz, transmitter, Transmitter) +ADD_SCENE(subghz, static, Static) +ADD_SCENE(subghz, test, Test) +ADD_SCENE(subghz, test_carrier, TestCarrier) +ADD_SCENE(subghz, test_packet, TestPacket) diff --git a/applications/subghz/scenes/subghz_scene_read.c b/applications/subghz/scenes/subghz_scene_read.c new file mode 100644 index 00000000..02906ff8 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_read.c @@ -0,0 +1,57 @@ +#include "../subghz_i.h" + +#define GUBGHZ_READ_CUSTOM_EVENT (10UL) + +void subghz_read_protocol_callback(SubGhzProtocolCommon* parser, void* context) { + furi_assert(context); + SubGhz* subghz = context; + subghz->protocol_result = parser; + view_dispatcher_send_custom_event(subghz->view_dispatcher, GUBGHZ_READ_CUSTOM_EVENT); +} +void subghz_scene_read_callback(DialogExResult result, void* context) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, result); +} + +const void subghz_scene_read_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + DialogEx* dialog_ex = subghz->dialog_ex; + + dialog_ex_set_header(dialog_ex, "SubGhz 433.92", 36, 6, AlignLeft, AlignCenter); + dialog_ex_set_icon(dialog_ex, 10, 12, &I_RFIDDolphinReceive_97x61); + + //Start CC1101 rx + subghz_begin(FuriHalSubGhzPresetOokAsync); + subghz_rx(433920000); + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->worker); + subghz_worker_start(subghz->worker); + subghz_protocol_enable_dump(subghz->protocol, subghz_read_protocol_callback, subghz); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewDialogEx); +} + +const bool subghz_scene_read_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GUBGHZ_READ_CUSTOM_EVENT) { + scene_manager_next_scene(subghz->scene_manager, SubGhzViewReceiver); + return true; + } + } + return false; +} + +const void subghz_scene_read_on_exit(void* context) { + SubGhz* subghz = context; + + //Stop CC1101 + subghz_worker_stop(subghz->worker); + furi_hal_subghz_stop_async_rx(); + subghz_end(); + + DialogEx* dialog_ex = subghz->dialog_ex; + dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); +} diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c new file mode 100644 index 00000000..1fe9a466 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -0,0 +1,37 @@ +#include "../subghz_i.h" +#include "../views/subghz_receiver.h" + +void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +const void subghz_scene_receiver_on_enter(void* context) { + SubGhz* subghz = context; + SubghzReceiver* subghz_receiver = subghz->subghz_receiver; + + subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz); + + subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); +} + +const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzReceverEventSave) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + return true; + } else if(event.event == SubghzReceverEventBack) { + scene_manager_previous_scene(subghz->scene_manager); + return true; + } + } + return false; +} + +const void subghz_scene_receiver_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c new file mode 100644 index 00000000..329c6931 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -0,0 +1,102 @@ +#include "../subghz_i.h" +#include +#include "file-worker.h" + +#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL) + +bool subghz_scene_save_data_to_file(void* context, const char* dev_name) { + SubGhz* subghz = context; + FileWorker* file_worker = file_worker_alloc(false); + string_t dev_file_name; + string_init(dev_file_name); + string_t temp_str; + string_init(temp_str); + bool saved = false; + + do { + // Create subghz folder directory if necessary + if(!file_worker_mkdir(file_worker, SUBGHZ_APP_FOLDER)) { + break; + } + // Create saved directory if necessary + if(!file_worker_mkdir(file_worker, SUBGHZ_APP_PATH_FOLDER)) { + break; + } + // First remove subghz device file if it was saved + string_printf( + dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); + if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { + break; + } + // Open file + if(!file_worker_open( + file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + break; + } + //Get string save + subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str); + // Prepare and write data to file + if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { + break; + } + saved = true; + } while(0); + + string_clear(temp_str); + string_clear(dev_file_name); + file_worker_close(file_worker); + file_worker_free(file_worker); + + return saved; +} + +void subghz_scene_save_name_text_input_callback(void* context) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_SAVE_NAME_CUSTOM_EVENT); +} + +const void subghz_scene_save_name_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + TextInput* text_input = subghz->text_input; + bool dev_name_empty = false; + + set_random_name(subghz->text_store, sizeof(subghz->text_store)); + dev_name_empty = true; + + text_input_set_header_text(text_input, "Name the KEY"); + text_input_set_result_callback( + text_input, + subghz_scene_save_name_text_input_callback, + subghz, + subghz->text_store, + 22, //Max len name + dev_name_empty); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput); +} + +const bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { + if(subghz_scene_save_data_to_file(subghz, subghz->text_store)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); + return true; + } else { + //Error save + return true; + } + } + } + return false; +} + +const void subghz_scene_save_name_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + text_input_set_header_text(subghz->text_input, NULL); + text_input_set_result_callback(subghz->text_input, NULL, NULL, NULL, 0, false); +} diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c new file mode 100644 index 00000000..4cbc9fcd --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -0,0 +1,47 @@ +#include "../subghz_i.h" + +#define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) + +void subghz_scene_save_success_popup_callback(void* context) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT); +} + +const void subghz_scene_save_success_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + Popup* popup = subghz->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, subghz); + popup_set_callback(popup, subghz_scene_save_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); +} + +const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) { + return scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + } + } + return false; +} + +const void subghz_scene_save_success_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + Popup* popup = subghz->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); +} diff --git a/applications/subghz/scenes/subghz_scene_saved.c b/applications/subghz/scenes/subghz_scene_saved.c new file mode 100644 index 00000000..d1dd058a --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_saved.c @@ -0,0 +1,88 @@ +#include "../subghz_i.h" + +bool subghz_scene_saved_file_select(SubGhz* subghz) { + furi_assert(subghz); + + FileWorker* file_worker = file_worker_alloc(false); + string_t protocol_file_name; + string_init(protocol_file_name); + string_t temp_str; + string_init(temp_str); + + // Input events and views are managed by file_select + bool res = file_worker_file_select( + file_worker, + SUBGHZ_APP_PATH_FOLDER, + SUBGHZ_APP_EXTENSION, + subghz->text_store, + sizeof(subghz->text_store), + NULL); + + if(res) { + // Get key file path + string_printf( + protocol_file_name, + "%s/%s%s", + SUBGHZ_APP_PATH_FOLDER, + subghz->text_store, + SUBGHZ_APP_EXTENSION); + } else { + string_clear(temp_str); + string_clear(protocol_file_name); + + file_worker_close(file_worker); + file_worker_free(file_worker); + return res; + } + + do { + if(!file_worker_open( + file_worker, string_get_cstr(protocol_file_name), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + // Read and parse name protocol from 1st line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + // strlen("Protocol: ") = 10 + string_right(temp_str, 10); + subghz->protocol_result = + subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); + if(subghz->protocol_result == NULL) { + file_worker_show_error(file_worker, "Cannot parse\nfile"); + break; + } + if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) { + file_worker_show_error(file_worker, "Cannot parse\nfile"); + break; + } + res = true; + } while(0); + + string_clear(temp_str); + string_clear(protocol_file_name); + + file_worker_close(file_worker); + file_worker_free(file_worker); + + return res; +} + +const void subghz_scene_saved_on_enter(void* context) { + SubGhz* subghz = context; + + if(subghz_scene_saved_file_select(subghz)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + } else { + scene_manager_search_and_switch_to_previous_scene(subghz->scene_manager, SubGhzSceneStart); + } +} + +const bool subghz_scene_saved_on_event(void* context, SceneManagerEvent event) { + // SubGhz* subghz = context; + return false; +} + +const void subghz_scene_saved_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c new file mode 100644 index 00000000..88b69962 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -0,0 +1,77 @@ +#include "../subghz_i.h" + +enum SubmenuIndex { + SubmenuIndexAnalyze, + SubmenuIndexRead, + SubmenuIndexSaved, + SubmenuIndexStatic, + SubmenuIndexTest, +}; + +void subghz_scene_start_submenu_callback(void* context, uint32_t index) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, index); +} + +const void subghz_scene_start_on_enter(void* context) { + SubGhz* subghz = context; + + submenu_add_item( + subghz->submenu, + "Analyze", + SubmenuIndexAnalyze, + subghz_scene_start_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, "Saved", SubmenuIndexSaved, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, "Static", SubmenuIndexStatic, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); + + submenu_set_selected_item( + subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart)); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); +} + +const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexAnalyze) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAnalyze); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneAnalyze); + return true; + } else if(event.event == SubmenuIndexRead) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRead); + return true; + } else if(event.event == SubmenuIndexSaved) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaved); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); + return true; + } else if(event.event == SubmenuIndexStatic) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexStatic); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStatic); + return true; + } else if(event.event == SubmenuIndexTest) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest); + return true; + } + } + return false; +} + +const void subghz_scene_start_on_exit(void* context) { + SubGhz* subghz = context; + submenu_clean(subghz->submenu); +} diff --git a/applications/subghz/scenes/subghz_scene_static.c b/applications/subghz/scenes/subghz_scene_static.c new file mode 100644 index 00000000..64d593d1 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_static.c @@ -0,0 +1,15 @@ +#include "../subghz_i.h" + +const void subghz_scene_static_on_enter(void* context) { + SubGhz* subghz = context; + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewStatic); +} + +const bool subghz_scene_static_on_event(void* context, SceneManagerEvent event) { + // SubGhz* subghz = context; + return false; +} + +const void subghz_scene_static_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_test.c b/applications/subghz/scenes/subghz_scene_test.c new file mode 100644 index 00000000..69b6c28e --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_test.c @@ -0,0 +1,53 @@ +#include "../subghz_i.h" + +enum SubmenuIndex { + SubmenuIndexCarrier, + SubmenuIndexPacket, +}; + +void subghz_scene_test_submenu_callback(void* context, uint32_t index) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, index); +} + +const void subghz_scene_test_on_enter(void* context) { + SubGhz* subghz = context; + + submenu_add_item( + subghz->submenu, + "Carrier", + SubmenuIndexCarrier, + subghz_scene_test_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, "Packet", SubmenuIndexPacket, subghz_scene_test_submenu_callback, subghz); + + submenu_set_selected_item( + subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); +} + +const bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexCarrier) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneTest, SubmenuIndexCarrier); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestCarrier); + return true; + } else if(event.event == SubmenuIndexPacket) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneTest, SubmenuIndexPacket); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestPacket); + return true; + } + } + return false; +} + +const void subghz_scene_test_on_exit(void* context) { + SubGhz* subghz = context; + submenu_clean(subghz->submenu); +} diff --git a/applications/subghz/scenes/subghz_scene_test_carrier.c b/applications/subghz/scenes/subghz_scene_test_carrier.c new file mode 100644 index 00000000..ef1fa1fc --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_test_carrier.c @@ -0,0 +1,15 @@ +#include "../subghz_i.h" + +const void subghz_scene_test_carrier_on_enter(void* context) { + SubGhz* subghz = context; + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestCarrier); +} + +const bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) { + // SubGhz* subghz = context; + return false; +} + +const void subghz_scene_test_carrier_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_test_packet.c b/applications/subghz/scenes/subghz_scene_test_packet.c new file mode 100644 index 00000000..7c275814 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_test_packet.c @@ -0,0 +1,15 @@ +#include "../subghz_i.h" + +const void subghz_scene_test_packet_on_enter(void* context) { + SubGhz* subghz = context; + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestPacket); +} + +const bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) { + // SubGhz* subghz = context; + return false; +} + +const void subghz_scene_test_packet_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c new file mode 100644 index 00000000..c2c9ce51 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -0,0 +1,65 @@ +#include "../subghz_i.h" +#include "../views/subghz_transmitter.h" +#include "lib/subghz/protocols/subghz_protocol_princeton.h" + +void subghz_scene_transmitter_tx(void* context) { + SubGhz* subghz = context; + SubGhzEncoderPrinceton* encoder = subghz_encoder_princeton_alloc(); + + subghz_encoder_princeton_reset(encoder, subghz->protocol_result->code_last_found, 4); + subghz_encoder_princeton_set_te(encoder, subghz->protocol_result); + + subghz_begin(FuriHalSubGhzPresetOokAsync); + subghz_tx(433920000); + + furi_hal_subghz_start_async_tx(subghz_encoder_princeton_yield, encoder); + + while(!furi_hal_subghz_is_async_tx_complete()) { + osDelay(20); + } + + //Stop tx + furi_hal_subghz_stop_async_tx(); + subghz_end(); + subghz_encoder_princeton_free(encoder); +} + +void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +const void subghz_scene_transmitter_on_enter(void* context) { + SubGhz* subghz = context; + SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; + + subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); + + subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); +} + +const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzTransmitterEventSend) { + //scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + subghz_scene_transmitter_tx(subghz); + return true; + } else if(event.event == SubghzTransmitterEventBack) { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + return true; + } + } + return false; +} + +const void subghz_scene_transmitter_on_exit(void* context) { + SubGhz* subghz = context; + SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; + + subghz_transmitter_set_callback(subghz_transmitter, NULL, subghz); +} diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 6190a72b..bf45208b 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -23,15 +23,22 @@ const uint32_t subghz_frequencies[] = { const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); const uint32_t subghz_frequencies_433_92 = 5; -void subghz_menu_callback(void* context, uint32_t index) { +bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhz* subghz = context; - - view_dispatcher_switch_to_view(subghz->view_dispatcher, index); + return scene_manager_handle_custom_event(subghz->scene_manager, event); } -uint32_t subghz_exit(void* context) { - return VIEW_NONE; +bool subghz_back_event_callback(void* context) { + furi_assert(context); + SubGhz* subghz = context; + return scene_manager_handle_back_event(subghz->scene_manager); +} + +void subghz_tick_event_callback(void* context) { + furi_assert(context); + SubGhz* subghz = context; + scene_manager_handle_tick_event(subghz->scene_manager); } SubGhz* subghz_alloc() { @@ -46,33 +53,62 @@ SubGhz* subghz_alloc() { view_dispatcher_attach_to_gui( subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); - // Menu + subghz->scene_manager = scene_manager_alloc(&subghz_scene_handlers, subghz); + view_dispatcher_set_event_callback_context(subghz->view_dispatcher, subghz); + view_dispatcher_set_custom_event_callback( + subghz->view_dispatcher, subghz_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + subghz->view_dispatcher, subghz_back_event_callback); + view_dispatcher_set_tick_event_callback( + subghz->view_dispatcher, subghz_tick_event_callback, 100); + + // SubMenu subghz->submenu = submenu_alloc(); - submenu_add_item(subghz->submenu, "Capture", SubGhzViewCapture, subghz_menu_callback, subghz); - submenu_add_item( - subghz->submenu, "Basic Test", SubGhzViewTestBasic, subghz_menu_callback, subghz); - submenu_add_item( - subghz->submenu, "Packet Test", SubGhzViewTestPacket, subghz_menu_callback, subghz); - submenu_add_item( - subghz->submenu, "Static Code", SubGhzViewStatic, subghz_menu_callback, subghz); + view_dispatcher_add_view( + subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu)); - View* submenu_view = submenu_get_view(subghz->submenu); - view_set_previous_callback(submenu_view, subghz_exit); - view_dispatcher_add_view(subghz->view_dispatcher, SubGhzViewMenu, submenu_view); - - // Capture - subghz->subghz_capture = subghz_capture_alloc(); + // Analyze + subghz->subghz_analyze = subghz_analyze_alloc(); view_dispatcher_add_view( subghz->view_dispatcher, - SubGhzViewCapture, - subghz_capture_get_view(subghz->subghz_capture)); + SubGhzViewAnalyze, + subghz_analyze_get_view(subghz->subghz_analyze)); - // Basic Test Module - subghz->subghz_test_basic = subghz_test_basic_alloc(); + // Receiver + subghz->subghz_receiver = subghz_receiver_alloc(); view_dispatcher_add_view( subghz->view_dispatcher, - SubGhzViewTestBasic, - subghz_test_basic_get_view(subghz->subghz_test_basic)); + SubGhzViewReceiver, + subghz_receiver_get_view(subghz->subghz_receiver)); + + // Dialog + subghz->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, SubGhzViewDialogEx, dialog_ex_get_view(subghz->dialog_ex)); + + // Popup + subghz->popup = popup_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, SubGhzViewPopup, popup_get_view(subghz->popup)); + + // Text Input + subghz->text_input = text_input_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input)); + + // Transmitter + subghz->subghz_transmitter = subghz_transmitter_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, + SubGhzViewTransmitter, + subghz_transmitter_get_view(subghz->subghz_transmitter)); + + // Carrier Test Module + subghz->subghz_test_carrier = subghz_test_carrier_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, + SubGhzViewTestCarrier, + subghz_test_carrier_get_view(subghz->subghz_test_carrier)); // Packet Test subghz->subghz_test_packet = subghz_test_packet_alloc(); @@ -86,8 +122,19 @@ SubGhz* subghz_alloc() { view_dispatcher_add_view( subghz->view_dispatcher, SubGhzViewStatic, subghz_static_get_view(subghz->subghz_static)); - // Switch to menu - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); + //init Worker & Protocol + subghz->worker = subghz_worker_alloc(); + subghz->protocol = subghz_protocol_alloc(); + subghz_worker_set_overrun_callback( + subghz->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); + subghz_worker_set_pair_callback( + subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); + subghz_worker_set_context(subghz->worker, subghz->protocol); + + subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes"); + subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx"); + + //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); return subghz; } @@ -95,25 +142,48 @@ SubGhz* subghz_alloc() { void subghz_free(SubGhz* subghz) { furi_assert(subghz); - // Packet Test - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic); - subghz_static_free(subghz->subghz_static); - // Packet Test view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestPacket); subghz_test_packet_free(subghz->subghz_test_packet); - // Basic Test - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestBasic); - subghz_test_basic_free(subghz->subghz_test_basic); + // Carrier Test + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestCarrier); + subghz_test_carrier_free(subghz->subghz_test_carrier); + + // Static + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic); + subghz_static_free(subghz->subghz_static); + + // Analyze + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze); + subghz_analyze_free(subghz->subghz_analyze); + + // Receiver + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver); + subghz_receiver_free(subghz->subghz_receiver); + + // TextInput + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); + text_input_free(subghz->text_input); + + // Receiver + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); + subghz_transmitter_free(subghz->subghz_transmitter); // Submenu view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); submenu_free(subghz->submenu); - // Capture - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewCapture); - subghz_capture_free(subghz->subghz_capture); + // DialogEx + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewDialogEx); + dialog_ex_free(subghz->dialog_ex); + + // Popup + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); + popup_free(subghz->popup); + + // Scene manager + scene_manager_free(subghz->scene_manager); // View Dispatcher view_dispatcher_free(subghz->view_dispatcher); @@ -122,13 +192,24 @@ void subghz_free(SubGhz* subghz) { furi_record_close("gui"); subghz->gui = NULL; + //Worker & Protocol + subghz_protocol_free(subghz->protocol); + subghz_worker_free(subghz->worker); + // The rest free(subghz); } -int32_t subghz_app(void* context) { +int32_t subghz_app(void* p) { SubGhz* subghz = subghz_alloc(); + // Check argument and run corresponding scene + if(p && subghz_key_load(subghz, p)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + } else { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); + } + view_dispatcher_run(subghz->view_dispatcher); subghz_free(subghz); diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index d6197869..9681fdef 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -4,6 +4,7 @@ #include #include #include +#include #define SUBGHZ_FREQUENCY_RANGE_STR \ "299999755...348000000 or 386999938...464000000 or 778999847...928000000" @@ -94,14 +95,10 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) { furi_hal_subghz_sleep(); } -#define SUBGHZ_PT_SHORT 376 -#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3) -#define SUBGHZ_PT_GUARD 10600 - void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { uint32_t frequency = 433920000; - size_t repeat = 10; uint32_t key = 0x0074BADE; + size_t repeat = 10; if(string_size(args)) { int ret = sscanf(string_get_cstr(args), "%lx %lu %u", &key, &frequency, &repeat); @@ -126,41 +123,31 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { } } - size_t subghz_test_data_size = 25 * 2 * sizeof(uint32_t); - uint32_t* subghz_test_data = furi_alloc(subghz_test_data_size); - - size_t pos = 0; - for(uint8_t i = 0; i < 24; i++) { - uint8_t byte = i / 8; - uint8_t bit = i % 8; - bool value = (((uint8_t*)&key)[2 - byte] >> (7 - bit)) & 1; - if(value) { - subghz_test_data[pos++] = SUBGHZ_PT_SHORT; - subghz_test_data[pos++] = SUBGHZ_PT_LONG; - } else { - subghz_test_data[pos++] = SUBGHZ_PT_LONG; - subghz_test_data[pos++] = SUBGHZ_PT_SHORT; - } - } - subghz_test_data[pos++] = SUBGHZ_PT_SHORT; - subghz_test_data[pos++] = SUBGHZ_PT_SHORT + SUBGHZ_PT_GUARD; - printf( "Transmitting at %lu, key %lx, repeat %u. Press CTRL+C to stop\r\n", frequency, key, repeat); + SubGhzEncoderPrinceton* encoder = subghz_encoder_princeton_alloc(); + subghz_encoder_princeton_reset(encoder, key, repeat); + furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_subghz_start_async_tx(subghz_test_data, subghz_test_data_size, repeat); - furi_hal_subghz_wait_async_tx(); + furi_hal_subghz_start_async_tx(subghz_encoder_princeton_yield, encoder); + + while(!furi_hal_subghz_is_async_tx_complete()) { + printf("."); + fflush(stdout); + osDelay(333); + } + furi_hal_subghz_stop_async_tx(); - free(subghz_test_data); furi_hal_subghz_sleep(); + subghz_encoder_princeton_free(encoder); } typedef struct { @@ -225,8 +212,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); // Prepare and start RX - furi_hal_subghz_set_async_rx_callback(subghz_cli_command_rx_callback, instance); - furi_hal_subghz_start_async_rx(); + furi_hal_subghz_start_async_rx(subghz_cli_command_rx_callback, instance); // Wait for packets to arrive printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c new file mode 100644 index 00000000..359b2651 --- /dev/null +++ b/applications/subghz/subghz_i.c @@ -0,0 +1,83 @@ +#include "subghz_i.h" + +#include +#include +#include +#include +#include +#include +#include "file-worker.h" + +void subghz_begin(FuriHalSubGhzPreset preset) { + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_preset(preset); + hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); +} + +void subghz_rx(uint32_t frequency) { + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + furi_hal_subghz_rx(); +} + +void subghz_tx(uint32_t frequency) { + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + hal_gpio_write(&gpio_cc1101_g0, true); + furi_hal_subghz_tx(); +} + +void subghz_idle(void) { + furi_hal_subghz_idle(); +} + +void subghz_end(void) { + furi_hal_subghz_sleep(); +} + +bool subghz_key_load(SubGhz* subghz, const char* file_path) { + furi_assert(subghz); + furi_assert(file_path); + + FileWorker* file_worker = file_worker_alloc(false); + // Load device data + bool loaded = false; + string_t path; + string_init_set_str(path, file_path); + string_t temp_str; + string_init(temp_str); + + do { + if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + // Read and parse name protocol from 1st line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + // strlen("Protocol: ") = 10 + string_right(temp_str, 10); + subghz->protocol_result = + subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); + if(subghz->protocol_result == NULL) { + file_worker_show_error(file_worker, "Cannot parse\nfile"); + break; + } + if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) { + file_worker_show_error(file_worker, "Cannot parse\nfile"); + break; + } + loaded = true; + } while(0); + + string_clear(temp_str); + string_clear(path); + file_worker_close(file_worker); + file_worker_free(file_worker); + + return loaded; +} diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index b2da67b6..a7a86a8c 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -1,16 +1,31 @@ #pragma once #include "subghz.h" -#include "views/subghz_capture.h" -#include "views/subghz_test_basic.h" -#include "views/subghz_test_packet.h" +#include "views/subghz_analyze.h" +#include "views/subghz_receiver.h" +#include "views/subghz_transmitter.h" #include "views/subghz_static.h" +#include "views/subghz_test_carrier.h" +#include "views/subghz_test_packet.h" + #include #include #include +#include #include #include +#include +#include +#include + +#include + +#include +#include +#include + +#define SUBGHZ_TEXT_STORE_SIZE 128 extern const uint32_t subghz_frequencies[]; extern const uint32_t subghz_frequencies_count; @@ -19,23 +34,47 @@ extern const uint32_t subghz_frequencies_433_92; struct SubGhz { Gui* gui; + SubGhzWorker* worker; + SubGhzProtocol* protocol; + SubGhzProtocolCommon* protocol_result; + + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; Submenu* submenu; + DialogEx* dialog_ex; + Popup* popup; + TextInput* text_input; + char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; - SubghzCapture* subghz_capture; - - SubghzTestBasic* subghz_test_basic; - - SubghzTestPacket* subghz_test_packet; - + SubghzAnalyze* subghz_analyze; + SubghzReceiver* subghz_receiver; + SubghzTransmitter* subghz_transmitter; SubghzStatic* subghz_static; + + SubghzTestCarrier* subghz_test_carrier; + SubghzTestPacket* subghz_test_packet; }; typedef enum { SubGhzViewMenu, - SubGhzViewCapture, - SubGhzViewTestBasic, - SubGhzViewTestPacket, + + SubGhzViewAnalyze, + SubGhzViewDialogEx, + SubGhzViewReceiver, + SubGhzViewPopup, + SubGhzViewTextInput, + SubGhzViewTransmitter, + SubGhzViewStatic, + SubGhzViewTestCarrier, + SubGhzViewTestPacket, } SubGhzView; + +void subghz_begin(FuriHalSubGhzPreset preset); +void subghz_rx(uint32_t frequency); +void subghz_tx(uint32_t frequency); +void subghz_idle(void); +void subghz_end(void); +bool subghz_key_load(SubGhz* subghz, const char* file_path); \ No newline at end of file diff --git a/applications/subghz/views/subghz_capture.c b/applications/subghz/views/subghz_analyze.c similarity index 52% rename from applications/subghz/views/subghz_capture.c rename to applications/subghz/views/subghz_analyze.c index c8927e95..7380a026 100644 --- a/applications/subghz/views/subghz_capture.c +++ b/applications/subghz/views/subghz_analyze.c @@ -1,4 +1,4 @@ -#include "subghz_capture.h" +#include "subghz_analyze.h" #include "../subghz_i.h" #include @@ -13,7 +13,7 @@ #include -struct SubghzCapture { +struct SubghzAnalyze { View* view; SubGhzWorker* worker; SubGhzProtocol* protocol; @@ -26,11 +26,11 @@ typedef struct { string_t text; uint16_t scene; SubGhzProtocolCommon parser; -} SubghzCaptureModel; +} SubghzAnalyzeModel; static const char subghz_symbols[] = {'-', '\\', '|', '/'}; -void subghz_capture_draw(Canvas* canvas, SubghzCaptureModel* model) { +void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) { char buffer[64]; canvas_set_color(canvas, ColorBlack); @@ -39,7 +39,7 @@ void subghz_capture_draw(Canvas* canvas, SubghzCaptureModel* model) { snprintf( buffer, sizeof(buffer), - "Capture: %03ld.%03ldMHz %c", + "Analyze: %03ld.%03ldMHz %c", model->real_frequency / 1000000 % 1000, model->real_frequency / 1000 % 1000, subghz_symbols[model->counter % 4]); @@ -63,46 +63,47 @@ void subghz_capture_draw(Canvas* canvas, SubghzCaptureModel* model) { } } -bool subghz_capture_input(InputEvent* event, void* context) { +bool subghz_analyze_input(InputEvent* event, void* context) { furi_assert(context); - SubghzCapture* subghz_capture = context; + SubghzAnalyze* subghz_analyze = context; + + if(event->type != InputTypeShort) return false; if(event->key == InputKeyBack) { return false; } with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { - bool reconfigure = false; - if(event->type == InputTypeShort) { - if(event->key == InputKeyLeft) { - if(model->frequency > 0) model->frequency--; - reconfigure = true; - } else if(event->key == InputKeyRight) { - if(model->frequency < subghz_frequencies_count - 1) model->frequency++; - reconfigure = true; - } + subghz_analyze->view, (SubghzAnalyzeModel * model) { + bool model_updated = false; + + if(event->key == InputKeyLeft) { + if(model->frequency > 0) model->frequency--; + model_updated = true; + } else if(event->key == InputKeyRight) { + if(model->frequency < subghz_frequencies_count - 1) model->frequency++; + model_updated = true; } - if(reconfigure) { + if(model_updated) { furi_hal_subghz_idle(); model->real_frequency = furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); furi_hal_subghz_rx(); } - return reconfigure; + return model_updated; }); return true; } -void subghz_capture_text_callback(string_t text, void* context) { +void subghz_analyze_text_callback(string_t text, void* context) { furi_assert(context); - SubghzCapture* subghz_capture = context; + SubghzAnalyze* subghz_analyze = context; with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { + subghz_analyze->view, (SubghzAnalyzeModel * model) { model->counter++; string_set(model->text, text); model->scene = 0; @@ -110,9 +111,9 @@ void subghz_capture_text_callback(string_t text, void* context) { }); } -void subghz_capture_protocol_callback(SubGhzProtocolCommon* parser, void* context) { +void subghz_analyze_protocol_callback(SubGhzProtocolCommon* parser, void* context) { furi_assert(context); - SubghzCapture* subghz_capture = context; + SubghzAnalyze* subghz_analyze = context; char buffer[64]; snprintf( buffer, @@ -128,7 +129,7 @@ void subghz_capture_protocol_callback(SubGhzProtocolCommon* parser, void* contex parser->btn); with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { + subghz_analyze->view, (SubghzAnalyzeModel * model) { model->counter++; model->parser = *parser; string_set(model->text, buffer); @@ -137,16 +138,16 @@ void subghz_capture_protocol_callback(SubGhzProtocolCommon* parser, void* contex }); } -void subghz_capture_enter(void* context) { +void subghz_analyze_enter(void* context) { furi_assert(context); - SubghzCapture* subghz_capture = context; + SubghzAnalyze* subghz_analyze = context; furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { + subghz_analyze->view, (SubghzAnalyzeModel * model) { model->frequency = subghz_frequencies_433_92; model->real_frequency = furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); @@ -156,83 +157,77 @@ void subghz_capture_enter(void* context) { hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_set_async_rx_callback(subghz_worker_rx_callback, subghz_capture->worker); - furi_hal_subghz_start_async_rx(); + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz_analyze->worker); - subghz_worker_start(subghz_capture->worker); + subghz_worker_start(subghz_analyze->worker); furi_hal_subghz_flush_rx(); furi_hal_subghz_rx(); } -void subghz_capture_exit(void* context) { +void subghz_analyze_exit(void* context) { furi_assert(context); - SubghzCapture* subghz_capture = context; + SubghzAnalyze* subghz_analyze = context; - subghz_worker_stop(subghz_capture->worker); + subghz_worker_stop(subghz_analyze->worker); furi_hal_subghz_stop_async_rx(); furi_hal_subghz_sleep(); } -uint32_t subghz_capture_back(void* context) { - return SubGhzViewMenu; -} - -SubghzCapture* subghz_capture_alloc() { - SubghzCapture* subghz_capture = furi_alloc(sizeof(SubghzCapture)); +SubghzAnalyze* subghz_analyze_alloc() { + SubghzAnalyze* subghz_analyze = furi_alloc(sizeof(SubghzAnalyze)); // View allocation and configuration - subghz_capture->view = view_alloc(); - view_allocate_model(subghz_capture->view, ViewModelTypeLocking, sizeof(SubghzCaptureModel)); - view_set_context(subghz_capture->view, subghz_capture); - view_set_draw_callback(subghz_capture->view, (ViewDrawCallback)subghz_capture_draw); - view_set_input_callback(subghz_capture->view, subghz_capture_input); - view_set_enter_callback(subghz_capture->view, subghz_capture_enter); - view_set_exit_callback(subghz_capture->view, subghz_capture_exit); - view_set_previous_callback(subghz_capture->view, subghz_capture_back); + subghz_analyze->view = view_alloc(); + view_allocate_model(subghz_analyze->view, ViewModelTypeLocking, sizeof(SubghzAnalyzeModel)); + view_set_context(subghz_analyze->view, subghz_analyze); + view_set_draw_callback(subghz_analyze->view, (ViewDrawCallback)subghz_analyze_draw); + view_set_input_callback(subghz_analyze->view, subghz_analyze_input); + view_set_enter_callback(subghz_analyze->view, subghz_analyze_enter); + view_set_exit_callback(subghz_analyze->view, subghz_analyze_exit); with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { + subghz_analyze->view, (SubghzAnalyzeModel * model) { string_init(model->text); return true; }); - subghz_capture->worker = subghz_worker_alloc(); - subghz_capture->protocol = subghz_protocol_alloc(); + subghz_analyze->worker = subghz_worker_alloc(); + subghz_analyze->protocol = subghz_protocol_alloc(); subghz_worker_set_overrun_callback( - subghz_capture->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); + subghz_analyze->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); subghz_worker_set_pair_callback( - subghz_capture->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); - subghz_worker_set_context(subghz_capture->worker, subghz_capture->protocol); + subghz_analyze->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); + subghz_worker_set_context(subghz_analyze->worker, subghz_analyze->protocol); subghz_protocol_load_keeloq_file( - subghz_capture->protocol, "/ext/assets/subghz/keeloq_mfcodes"); + subghz_analyze->protocol, "/ext/assets/subghz/keeloq_mfcodes"); subghz_protocol_load_nice_flor_s_file( - subghz_capture->protocol, "/ext/assets/subghz/nice_floor_s_rx"); + subghz_analyze->protocol, "/ext/assets/subghz/nice_floor_s_rx"); subghz_protocol_enable_dump_text( - subghz_capture->protocol, subghz_capture_text_callback, subghz_capture); + subghz_analyze->protocol, subghz_analyze_text_callback, subghz_analyze); - return subghz_capture; + return subghz_analyze; } -void subghz_capture_free(SubghzCapture* subghz_capture) { - furi_assert(subghz_capture); +void subghz_analyze_free(SubghzAnalyze* subghz_analyze) { + furi_assert(subghz_analyze); - subghz_protocol_free(subghz_capture->protocol); - subghz_worker_free(subghz_capture->worker); + subghz_protocol_free(subghz_analyze->protocol); + subghz_worker_free(subghz_analyze->worker); with_view_model( - subghz_capture->view, (SubghzCaptureModel * model) { + subghz_analyze->view, (SubghzAnalyzeModel * model) { string_clear(model->text); return true; }); - view_free(subghz_capture->view); - free(subghz_capture); + view_free(subghz_analyze->view); + free(subghz_analyze); } -View* subghz_capture_get_view(SubghzCapture* subghz_capture) { - furi_assert(subghz_capture); - return subghz_capture->view; +View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze) { + furi_assert(subghz_analyze); + return subghz_analyze->view; } diff --git a/applications/subghz/views/subghz_analyze.h b/applications/subghz/views/subghz_analyze.h new file mode 100644 index 00000000..b1a553e6 --- /dev/null +++ b/applications/subghz/views/subghz_analyze.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef struct SubghzAnalyze SubghzAnalyze; + +SubghzAnalyze* subghz_analyze_alloc(); + +void subghz_analyze_free(SubghzAnalyze* subghz_analyze); + +View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze); diff --git a/applications/subghz/views/subghz_capture.h b/applications/subghz/views/subghz_capture.h deleted file mode 100644 index 84159cf5..00000000 --- a/applications/subghz/views/subghz_capture.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -typedef struct SubghzCapture SubghzCapture; - -SubghzCapture* subghz_capture_alloc(); - -void subghz_capture_free(SubghzCapture* subghz_capture); - -View* subghz_capture_get_view(SubghzCapture* subghz_capture); diff --git a/applications/subghz/views/subghz_receiver.c b/applications/subghz/views/subghz_receiver.c new file mode 100644 index 00000000..11b030d1 --- /dev/null +++ b/applications/subghz/views/subghz_receiver.c @@ -0,0 +1,146 @@ +#include "subghz_receiver.h" +#include "../subghz_i.h" + +#include +#include +#include +#include +#include +#include + +#include + +struct SubghzReceiver { + View* view; + SubghzReceiverCallback callback; + void* context; +}; + +typedef struct { + string_t text; + uint16_t scene; + SubGhzProtocolCommon* protocol; +} SubghzReceiverModel; + +void subghz_receiver_set_callback( + SubghzReceiver* subghz_receiver, + SubghzReceiverCallback callback, + void* context) { + furi_assert(subghz_receiver); + furi_assert(callback); + subghz_receiver->callback = callback; + subghz_receiver->context = context; +} + +void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol) { + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + model->protocol = protocol; + return true; + }); +} + +void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text)); + + elements_button_left(canvas, "Back"); + if(model->protocol && model->protocol->to_save_string) { + elements_button_right(canvas, "Save"); + } +} + +bool subghz_receiver_input(InputEvent* event, void* context) { + furi_assert(context); + SubghzReceiver* subghz_receiver = context; + + if(event->type != InputTypeShort) return false; + + bool can_be_saved = false; + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + can_be_saved = (model->protocol && model->protocol->to_save_string); + return false; + }); + + if(event->key == InputKeyBack) { + return false; + } else if(event->key == InputKeyLeft) { + subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); + } else if(can_be_saved && event->key == InputKeyRight) { + subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); + } + + return true; +} + +void subghz_receiver_text_callback(string_t text, void* context) { + furi_assert(context); + SubghzReceiver* subghz_receiver = context; + + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + string_set(model->text, text); + model->scene = 0; + return true; + }); +} + +void subghz_receiver_enter(void* context) { + furi_assert(context); + SubghzReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + model->protocol->to_string(model->protocol, model->text); + return true; + }); +} + +void subghz_receiver_exit(void* context) { + furi_assert(context); + SubghzReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + string_clean(model->text); + return true; + }); +} + +SubghzReceiver* subghz_receiver_alloc() { + SubghzReceiver* subghz_receiver = furi_alloc(sizeof(SubghzReceiver)); + + // View allocation and configuration + subghz_receiver->view = view_alloc(); + view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel)); + view_set_context(subghz_receiver->view, subghz_receiver); + view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw); + view_set_input_callback(subghz_receiver->view, subghz_receiver_input); + view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter); + view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit); + + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + string_init(model->text); + return true; + }); + return subghz_receiver; +} + +void subghz_receiver_free(SubghzReceiver* subghz_receiver) { + furi_assert(subghz_receiver); + + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + string_clear(model->text); + return true; + }); + view_free(subghz_receiver->view); + free(subghz_receiver); +} + +View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { + furi_assert(subghz_receiver); + return subghz_receiver->view; +} diff --git a/applications/subghz/views/subghz_receiver.h b/applications/subghz/views/subghz_receiver.h new file mode 100644 index 00000000..924f90b8 --- /dev/null +++ b/applications/subghz/views/subghz_receiver.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +typedef enum { + SubghzReceverEventSave, + SubghzReceverEventBack, +} SubghzReceverEvent; + +typedef struct SubghzReceiver SubghzReceiver; + +typedef void (*SubghzReceiverCallback)(SubghzReceverEvent event, void* context); + +void subghz_receiver_set_callback( + SubghzReceiver* subghz_receiver, + SubghzReceiverCallback callback, + void* context); + +SubghzReceiver* subghz_receiver_alloc(); + +void subghz_receiver_free(SubghzReceiver* subghz_receiver); + +View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); + +void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol); diff --git a/applications/subghz/views/subghz_static.c b/applications/subghz/views/subghz_static.c index 0dd91e60..52bf0ae6 100644 --- a/applications/subghz/views/subghz_static.c +++ b/applications/subghz/views/subghz_static.c @@ -6,20 +6,18 @@ #include #include #include +#include -static const uint8_t subghz_static_keys[][4] = { - {0x74, 0xBA, 0xDE}, - {0x74, 0xBA, 0xDD}, - {0x74, 0xBA, 0xDB}, - {0xE3, 0x4A, 0x4E}, +static const uint32_t subghz_static_keys[] = { + 0x0074BADE, + 0x0074BADD, + 0x0074BADB, + 0x00E34A4E, }; -#define SUBGHZ_PT_SHORT 376 -#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3) -#define SUBGHZ_PT_GUARD 10600 - struct SubghzStatic { View* view; + SubGhzEncoderPrinceton* encoder; }; typedef enum { @@ -56,14 +54,14 @@ void subghz_static_draw(Canvas* canvas, SubghzStaticModel* model) { bool subghz_static_input(InputEvent* event, void* context) { furi_assert(context); - SubghzStatic* subghz_static = context; + SubghzStatic* instance = context; if(event->key == InputKeyBack) { return false; } with_view_model( - subghz_static->view, (SubghzStaticModel * model) { + instance->view, (SubghzStaticModel * model) { bool reconfigure = false; if(event->type == InputTypeShort) { if(event->key == InputKeyLeft) { @@ -88,31 +86,16 @@ bool subghz_static_input(InputEvent* event, void* context) { if(event->key == InputKeyOk) { if(event->type == InputTypePress) { - const uint8_t* key = subghz_static_keys[model->button]; - NotificationApp* notification = furi_record_open("notification"); notification_message_block(notification, &sequence_set_red_255); - __disable_irq(); - for(uint8_t r = 0; r < 20; r++) { - //Payload - for(uint8_t i = 0; i < 24; i++) { - uint8_t byte = i / 8; - uint8_t bit = i % 8; - bool value = (key[byte] >> (7 - bit)) & 1; - // Payload send - hal_gpio_write(&gpio_cc1101_g0, true); - delay_us(value ? SUBGHZ_PT_SHORT : SUBGHZ_PT_LONG); - hal_gpio_write(&gpio_cc1101_g0, false); - delay_us(value ? SUBGHZ_PT_LONG : SUBGHZ_PT_SHORT); - } - // Last bit - hal_gpio_write(&gpio_cc1101_g0, true); - delay_us(SUBGHZ_PT_SHORT); - hal_gpio_write(&gpio_cc1101_g0, false); - // Guard time - delay_us(10600); - } - __enable_irq(); + + subghz_encoder_princeton_reset( + instance->encoder, subghz_static_keys[model->button], 20); + furi_hal_subghz_start_async_tx( + subghz_encoder_princeton_yield, instance->encoder); + while(!furi_hal_subghz_is_async_tx_complete()) osDelay(33); + furi_hal_subghz_stop_async_tx(); + notification_message(notification, &sequence_reset_red); furi_record_close("notification"); } @@ -126,7 +109,7 @@ bool subghz_static_input(InputEvent* event, void* context) { void subghz_static_enter(void* context) { furi_assert(context); - SubghzStatic* subghz_static = context; + SubghzStatic* instance = context; furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); @@ -135,7 +118,7 @@ void subghz_static_enter(void* context) { hal_gpio_write(&gpio_cc1101_g0, false); with_view_model( - subghz_static->view, (SubghzStaticModel * model) { + instance->view, (SubghzStaticModel * model) { model->frequency = subghz_frequencies_433_92; model->real_frequency = furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); @@ -148,39 +131,34 @@ void subghz_static_enter(void* context) { void subghz_static_exit(void* context) { furi_assert(context); - // SubghzStatic* subghz_static = context; - - // Reinitialize IC to default state furi_hal_subghz_sleep(); } -uint32_t subghz_static_back(void* context) { - return SubGhzViewMenu; -} - SubghzStatic* subghz_static_alloc() { - SubghzStatic* subghz_static = furi_alloc(sizeof(SubghzStatic)); + SubghzStatic* instance = furi_alloc(sizeof(SubghzStatic)); // View allocation and configuration - subghz_static->view = view_alloc(); - view_allocate_model(subghz_static->view, ViewModelTypeLockFree, sizeof(SubghzStaticModel)); - view_set_context(subghz_static->view, subghz_static); - view_set_draw_callback(subghz_static->view, (ViewDrawCallback)subghz_static_draw); - view_set_input_callback(subghz_static->view, subghz_static_input); - view_set_enter_callback(subghz_static->view, subghz_static_enter); - view_set_exit_callback(subghz_static->view, subghz_static_exit); - view_set_previous_callback(subghz_static->view, subghz_static_back); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(SubghzStaticModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_static_draw); + view_set_input_callback(instance->view, subghz_static_input); + view_set_enter_callback(instance->view, subghz_static_enter); + view_set_exit_callback(instance->view, subghz_static_exit); - return subghz_static; + instance->encoder = subghz_encoder_princeton_alloc(); + + return instance; } -void subghz_static_free(SubghzStatic* subghz_static) { - furi_assert(subghz_static); - view_free(subghz_static->view); - free(subghz_static); +void subghz_static_free(SubghzStatic* instance) { + furi_assert(instance); + subghz_encoder_princeton_free(instance->encoder); + view_free(instance->view); + free(instance); } -View* subghz_static_get_view(SubghzStatic* subghz_static) { - furi_assert(subghz_static); - return subghz_static->view; +View* subghz_static_get_view(SubghzStatic* instance) { + furi_assert(instance); + return instance->view; } diff --git a/applications/subghz/views/subghz_test_basic.h b/applications/subghz/views/subghz_test_basic.h deleted file mode 100644 index 5229c7c6..00000000 --- a/applications/subghz/views/subghz_test_basic.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -typedef struct SubghzTestBasic SubghzTestBasic; - -SubghzTestBasic* subghz_test_basic_alloc(); - -void subghz_test_basic_free(SubghzTestBasic* subghz_test_basic); - -View* subghz_test_basic_get_view(SubghzTestBasic* subghz_test_basic); diff --git a/applications/subghz/views/subghz_test_basic.c b/applications/subghz/views/subghz_test_carrier.c similarity index 57% rename from applications/subghz/views/subghz_test_basic.c rename to applications/subghz/views/subghz_test_carrier.c index 1c954ad6..14fb9daa 100644 --- a/applications/subghz/views/subghz_test_basic.c +++ b/applications/subghz/views/subghz_test_carrier.c @@ -1,4 +1,4 @@ -#include "subghz_test_basic.h" +#include "subghz_test_carrier.h" #include "../subghz_i.h" #include @@ -6,25 +6,25 @@ #include #include -struct SubghzTestBasic { +struct SubghzTestCarrier { View* view; osTimerId timer; }; typedef enum { - SubghzTestBasicModelStatusRx, - SubghzTestBasicModelStatusTx, -} SubghzTestBasicModelStatus; + SubghzTestCarrierModelStatusRx, + SubghzTestCarrierModelStatusTx, +} SubghzTestCarrierModelStatus; typedef struct { uint8_t frequency; uint32_t real_frequency; FuriHalSubGhzPath path; float rssi; - SubghzTestBasicModelStatus status; -} SubghzTestBasicModel; + SubghzTestCarrierModelStatus status; +} SubghzTestCarrierModel; -void subghz_test_basic_draw(Canvas* canvas, SubghzTestBasicModel* model) { +void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) { char buffer[64]; canvas_set_color(canvas, ColorBlack); @@ -54,7 +54,7 @@ void subghz_test_basic_draw(Canvas* canvas, SubghzTestBasicModel* model) { } snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); canvas_draw_str(canvas, 0, 31, buffer); - if(model->status == SubghzTestBasicModelStatusRx) { + if(model->status == SubghzTestCarrierModelStatusRx) { snprintf( buffer, sizeof(buffer), @@ -67,17 +67,17 @@ void subghz_test_basic_draw(Canvas* canvas, SubghzTestBasicModel* model) { } } -bool subghz_test_basic_input(InputEvent* event, void* context) { +bool subghz_test_carrier_input(InputEvent* event, void* context) { furi_assert(context); - SubghzTestBasic* subghz_test_basic = context; + SubghzTestCarrier* subghz_test_carrier = context; if(event->key == InputKeyBack) { return false; } with_view_model( - subghz_test_basic->view, (SubghzTestBasicModel * model) { - osTimerStop(subghz_test_basic->timer); + subghz_test_carrier->view, (SubghzTestCarrierModel * model) { + osTimerStop(subghz_test_carrier->timer); furi_hal_subghz_idle(); if(event->type == InputTypeShort) { @@ -90,10 +90,10 @@ bool subghz_test_basic_input(InputEvent* event, void* context) { } else if(event->key == InputKeyUp) { if(model->path < FuriHalSubGhzPath868) model->path++; } else if(event->key == InputKeyOk) { - if(model->status == SubghzTestBasicModelStatusTx) { - model->status = SubghzTestBasicModelStatusRx; + if(model->status == SubghzTestCarrierModelStatusTx) { + model->status = SubghzTestCarrierModelStatusRx; } else { - model->status = SubghzTestBasicModelStatusTx; + model->status = SubghzTestCarrierModelStatusTx; } } @@ -102,10 +102,10 @@ bool subghz_test_basic_input(InputEvent* event, void* context) { furi_hal_subghz_set_path(model->path); } - if(model->status == SubghzTestBasicModelStatusRx) { + if(model->status == SubghzTestCarrierModelStatusRx) { hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_rx(); - osTimerStart(subghz_test_basic->timer, 1024 / 4); + osTimerStart(subghz_test_carrier->timer, 1024 / 4); } else { hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); hal_gpio_write(&gpio_cc1101_g0, true); @@ -118,9 +118,9 @@ bool subghz_test_basic_input(InputEvent* event, void* context) { return true; } -void subghz_test_basic_enter(void* context) { +void subghz_test_carrier_enter(void* context) { furi_assert(context); - SubghzTestBasic* subghz_test_basic = context; + SubghzTestCarrier* subghz_test_carrier = context; furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); @@ -128,74 +128,69 @@ void subghz_test_basic_enter(void* context) { hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); with_view_model( - subghz_test_basic->view, (SubghzTestBasicModel * model) { + subghz_test_carrier->view, (SubghzTestCarrierModel * model) { model->frequency = subghz_frequencies_433_92; // 433 model->real_frequency = furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); model->path = FuriHalSubGhzPathIsolate; // isolate model->rssi = 0.0f; - model->status = SubghzTestBasicModelStatusRx; + model->status = SubghzTestCarrierModelStatusRx; return true; }); furi_hal_subghz_rx(); - osTimerStart(subghz_test_basic->timer, 1024 / 4); + osTimerStart(subghz_test_carrier->timer, 1024 / 4); } -void subghz_test_basic_exit(void* context) { +void subghz_test_carrier_exit(void* context) { furi_assert(context); - SubghzTestBasic* subghz_test_basic = context; + SubghzTestCarrier* subghz_test_carrier = context; - osTimerStop(subghz_test_basic->timer); + osTimerStop(subghz_test_carrier->timer); // Reinitialize IC to default state furi_hal_subghz_sleep(); } -void subghz_test_basic_rssi_timer_callback(void* context) { +void subghz_test_carrier_rssi_timer_callback(void* context) { furi_assert(context); - SubghzTestBasic* subghz_test_basic = context; + SubghzTestCarrier* subghz_test_carrier = context; with_view_model( - subghz_test_basic->view, (SubghzTestBasicModel * model) { + subghz_test_carrier->view, (SubghzTestCarrierModel * model) { model->rssi = furi_hal_subghz_get_rssi(); return true; }); } -uint32_t subghz_test_basic_back(void* context) { - return SubGhzViewMenu; -} - -SubghzTestBasic* subghz_test_basic_alloc() { - SubghzTestBasic* subghz_test_basic = furi_alloc(sizeof(SubghzTestBasic)); +SubghzTestCarrier* subghz_test_carrier_alloc() { + SubghzTestCarrier* subghz_test_carrier = furi_alloc(sizeof(SubghzTestCarrier)); // View allocation and configuration - subghz_test_basic->view = view_alloc(); + subghz_test_carrier->view = view_alloc(); view_allocate_model( - subghz_test_basic->view, ViewModelTypeLockFree, sizeof(SubghzTestBasicModel)); - view_set_context(subghz_test_basic->view, subghz_test_basic); - view_set_draw_callback(subghz_test_basic->view, (ViewDrawCallback)subghz_test_basic_draw); - view_set_input_callback(subghz_test_basic->view, subghz_test_basic_input); - view_set_enter_callback(subghz_test_basic->view, subghz_test_basic_enter); - view_set_exit_callback(subghz_test_basic->view, subghz_test_basic_exit); - view_set_previous_callback(subghz_test_basic->view, subghz_test_basic_back); + subghz_test_carrier->view, ViewModelTypeLockFree, sizeof(SubghzTestCarrierModel)); + view_set_context(subghz_test_carrier->view, subghz_test_carrier); + view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw); + view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input); + view_set_enter_callback(subghz_test_carrier->view, subghz_test_carrier_enter); + view_set_exit_callback(subghz_test_carrier->view, subghz_test_carrier_exit); - subghz_test_basic->timer = osTimerNew( - subghz_test_basic_rssi_timer_callback, osTimerPeriodic, subghz_test_basic, NULL); + subghz_test_carrier->timer = osTimerNew( + subghz_test_carrier_rssi_timer_callback, osTimerPeriodic, subghz_test_carrier, NULL); - return subghz_test_basic; + return subghz_test_carrier; } -void subghz_test_basic_free(SubghzTestBasic* subghz_test_basic) { - furi_assert(subghz_test_basic); - osTimerDelete(subghz_test_basic->timer); - view_free(subghz_test_basic->view); - free(subghz_test_basic); +void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier) { + furi_assert(subghz_test_carrier); + osTimerDelete(subghz_test_carrier->timer); + view_free(subghz_test_carrier->view); + free(subghz_test_carrier); } -View* subghz_test_basic_get_view(SubghzTestBasic* subghz_test_basic) { - furi_assert(subghz_test_basic); - return subghz_test_basic->view; +View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier) { + furi_assert(subghz_test_carrier); + return subghz_test_carrier->view; } diff --git a/applications/subghz/views/subghz_test_carrier.h b/applications/subghz/views/subghz_test_carrier.h new file mode 100644 index 00000000..f191f7af --- /dev/null +++ b/applications/subghz/views/subghz_test_carrier.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef struct SubghzTestCarrier SubghzTestCarrier; + +SubghzTestCarrier* subghz_test_carrier_alloc(); + +void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier); + +View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier); diff --git a/applications/subghz/views/subghz_test_packet.c b/applications/subghz/views/subghz_test_packet.c index 530585e5..44841af2 100644 --- a/applications/subghz/views/subghz_test_packet.c +++ b/applications/subghz/views/subghz_test_packet.c @@ -10,16 +10,12 @@ #define SUBGHZ_TEST_PACKET_COUNT 1000 -#define SUBGHZ_PT_SHORT 376 -#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3) -#define SUBGHZ_PT_GUARD 10600 - struct SubghzTestPacket { View* view; osTimerId timer; - size_t tx_buffer_size; - uint32_t* tx_buffer; - SubGhzProtocolPrinceton* princeton; + + SubGhzDecoderPrinceton* decoder; + SubGhzEncoderPrinceton* encoder; volatile size_t packet_rx; }; @@ -43,7 +39,7 @@ volatile bool subghz_test_packet_overrun = false; static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) { furi_assert(context); SubghzTestPacket* instance = context; - subghz_protocol_princeton_parse(instance->princeton, level, duration); + subghz_decoder_princeton_parse(instance->decoder, level, duration); } static void subghz_test_packet_rx_pt_callback(SubGhzProtocolCommon* parser, void* context) { @@ -62,8 +58,8 @@ static void subghz_test_packet_rssi_timer_callback(void* context) { model->rssi = furi_hal_subghz_get_rssi(); model->packets = instance->packet_rx; } else { - model->packets = - SUBGHZ_TEST_PACKET_COUNT - furi_hal_subghz_get_async_tx_repeat_left(); + model->packets = SUBGHZ_TEST_PACKET_COUNT - + subghz_encoder_princeton_get_repeat_left(instance->encoder); } return true; }); @@ -155,10 +151,10 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { } if(model->status == SubghzTestPacketModelStatusRx) { - furi_hal_subghz_start_async_rx(); + furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); } else { - furi_hal_subghz_start_async_tx( - instance->tx_buffer, instance->tx_buffer_size, SUBGHZ_TEST_PACKET_COUNT); + subghz_encoder_princeton_reset(instance->encoder, 0x00AABBCC, 1000); + furi_hal_subghz_start_async_tx(subghz_encoder_princeton_yield, instance->encoder); } return true; @@ -171,30 +167,8 @@ void subghz_test_packet_enter(void* context) { furi_assert(context); SubghzTestPacket* instance = context; - instance->tx_buffer_size = 25 * 2 * sizeof(uint32_t); - instance->tx_buffer = furi_alloc(instance->tx_buffer_size); - - const uint32_t key = 0x00ABCDEF; - - size_t pos = 0; - for(uint8_t i = 0; i < 24; i++) { - uint8_t byte = i / 8; - uint8_t bit = i % 8; - bool value = (((uint8_t*)&key)[2 - byte] >> (7 - bit)) & 1; - if(value) { - instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT; - instance->tx_buffer[pos++] = SUBGHZ_PT_LONG; - } else { - instance->tx_buffer[pos++] = SUBGHZ_PT_LONG; - instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT; - } - } - instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT; - instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT + SUBGHZ_PT_GUARD; - furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); - furi_hal_subghz_set_async_rx_callback(subghz_test_packet_rx_callback, instance); with_view_model( instance->view, (SubghzTestPacketModel * model) { @@ -207,7 +181,7 @@ void subghz_test_packet_enter(void* context) { return true; }); - furi_hal_subghz_start_async_rx(); + furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); osTimerStart(instance->timer, 1024 / 4); } @@ -228,14 +202,9 @@ void subghz_test_packet_exit(void* context) { } return true; }); - furi_hal_subghz_set_async_rx_callback(NULL, NULL); furi_hal_subghz_sleep(); } -uint32_t subghz_test_packet_back(void* context) { - return SubGhzViewMenu; -} - SubghzTestPacket* subghz_test_packet_alloc() { SubghzTestPacket* instance = furi_alloc(sizeof(SubghzTestPacket)); @@ -247,14 +216,14 @@ SubghzTestPacket* subghz_test_packet_alloc() { view_set_input_callback(instance->view, subghz_test_packet_input); view_set_enter_callback(instance->view, subghz_test_packet_enter); view_set_exit_callback(instance->view, subghz_test_packet_exit); - view_set_previous_callback(instance->view, subghz_test_packet_back); instance->timer = osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL); - instance->princeton = subghz_protocol_princeton_alloc(); + instance->decoder = subghz_decoder_princeton_alloc(); subghz_protocol_common_set_callback( - (SubGhzProtocolCommon*)instance->princeton, subghz_test_packet_rx_pt_callback, instance); + (SubGhzProtocolCommon*)instance->decoder, subghz_test_packet_rx_pt_callback, instance); + instance->encoder = subghz_encoder_princeton_alloc(); return instance; } @@ -262,7 +231,9 @@ SubghzTestPacket* subghz_test_packet_alloc() { void subghz_test_packet_free(SubghzTestPacket* instance) { furi_assert(instance); - subghz_protocol_princeton_free(instance->princeton); + subghz_decoder_princeton_free(instance->decoder); + subghz_encoder_princeton_free(instance->encoder); + osTimerDelete(instance->timer); view_free(instance->view); free(instance); diff --git a/applications/subghz/views/subghz_transmitter.c b/applications/subghz/views/subghz_transmitter.c new file mode 100644 index 00000000..703d00d8 --- /dev/null +++ b/applications/subghz/views/subghz_transmitter.c @@ -0,0 +1,138 @@ +#include "subghz_transmitter.h" +#include "../subghz_i.h" + +#include +#include +#include +#include +#include +#include + +#include + +struct SubghzTransmitter { + View* view; + SubghzTransmitterCallback callback; + void* context; +}; + +typedef struct { + string_t text; + uint16_t scene; + SubGhzProtocolCommon* protocol; +} SubghzTransmitterModel; + +void subghz_transmitter_set_callback( + SubghzTransmitter* subghz_transmitter, + SubghzTransmitterCallback callback, + void* context) { + furi_assert(subghz_transmitter); + + subghz_transmitter->callback = callback; + subghz_transmitter->context = context; +} + +void subghz_transmitter_set_protocol( + SubghzTransmitter* subghz_transmitter, + SubGhzProtocolCommon* protocol) { + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + model->protocol = protocol; + return true; + }); +} + +void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text)); + + elements_button_center(canvas, "Send"); +} + +bool subghz_transmitter_input(InputEvent* event, void* context) { + furi_assert(context); + SubghzTransmitter* subghz_transmitter = context; + + if(event->type != InputTypeShort) return false; + + if(event->key == InputKeyBack) { + return false; + } else if(event->key == InputKeyOk) { + subghz_transmitter->callback(SubghzTransmitterEventSend, subghz_transmitter->context); + return true; + } + + return true; +} + +void subghz_transmitter_text_callback(string_t text, void* context) { + furi_assert(context); + SubghzTransmitter* subghz_transmitter = context; + + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + string_set(model->text, text); + model->scene = 0; + return true; + }); +} + +void subghz_transmitter_enter(void* context) { + furi_assert(context); + SubghzTransmitter* subghz_transmitter = context; + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + model->protocol->to_string(model->protocol, model->text); + return true; + }); +} + +void subghz_transmitter_exit(void* context) { + furi_assert(context); + SubghzTransmitter* subghz_transmitter = context; + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + string_clean(model->text); + return true; + }); +} + +SubghzTransmitter* subghz_transmitter_alloc() { + SubghzTransmitter* subghz_transmitter = furi_alloc(sizeof(SubghzTransmitter)); + + // View allocation and configuration + subghz_transmitter->view = view_alloc(); + view_allocate_model( + subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubghzTransmitterModel)); + view_set_context(subghz_transmitter->view, subghz_transmitter); + view_set_draw_callback(subghz_transmitter->view, (ViewDrawCallback)subghz_transmitter_draw); + view_set_input_callback(subghz_transmitter->view, subghz_transmitter_input); + view_set_enter_callback(subghz_transmitter->view, subghz_transmitter_enter); + view_set_exit_callback(subghz_transmitter->view, subghz_transmitter_exit); + + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + string_init(model->text); + return true; + }); + return subghz_transmitter; +} + +void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { + furi_assert(subghz_transmitter); + + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + string_clear(model->text); + return true; + }); + view_free(subghz_transmitter->view); + free(subghz_transmitter); +} + +View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter) { + furi_assert(subghz_transmitter); + return subghz_transmitter->view; +} diff --git a/applications/subghz/views/subghz_transmitter.h b/applications/subghz/views/subghz_transmitter.h new file mode 100644 index 00000000..ffd27373 --- /dev/null +++ b/applications/subghz/views/subghz_transmitter.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +typedef enum { + SubghzTransmitterEventSend, + SubghzTransmitterEventBack, +} SubghzTransmitterEvent; + +typedef struct SubghzTransmitter SubghzTransmitter; + +typedef void (*SubghzTransmitterCallback)(SubghzTransmitterEvent event, void* context); + +void subghz_transmitter_set_callback( + SubghzTransmitter* subghz_transmitter, + SubghzTransmitterCallback callback, + void* context); + +SubghzTransmitter* subghz_transmitter_alloc(); + +void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter); + +View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); + +void subghz_transmitter_set_protocol( + SubghzTransmitter* subghz_transmitter, + SubGhzProtocolCommon* protocol); diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index 105b5801..62cd2668 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -40,8 +40,9 @@ static const uint8_t furi_hal_subghz_preset_ook_async_regs[][2] = { { CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off /* Automatic Gain Control */ - { CC1101_AGCTRL1, 0x00 }, // LNA 2 gain is decreased to minimum before decreasing LNA gain - { CC1101_AGCTRL2, 0x07 }, // MAGN_TARGET is 42 dB + { CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + { CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + { CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB /* Wake on radio and timeouts control */ { CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours @@ -323,15 +324,14 @@ static void furi_hal_subghz_capture_ISR() { } } -void furi_hal_subghz_set_async_rx_callback(FuriHalSubGhzCaptureCallback callback, void* context) { - furi_hal_subghz_capture_callback = callback; - furi_hal_subghz_capture_callback_context = context; -} -void furi_hal_subghz_start_async_rx() { +void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) { furi_assert(furi_hal_subghz_state == SubGhzStateIdle); furi_hal_subghz_state = SubGhzStateAsyncRx; + furi_hal_subghz_capture_callback = callback; + furi_hal_subghz_capture_callback_context = context; + hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); // Timer: base @@ -402,33 +402,73 @@ void furi_hal_subghz_stop_async_rx() { hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -volatile size_t furi_hal_subghz_tx_repeat = 0; +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL/2) -static void furi_hal_subghz_tx_dma_isr() { +typedef struct { + uint32_t* buffer; + bool flip_flop; + FuriHalSubGhzAsyncTxCallback callback; + void* callback_context; +} FuriHalSubGhzAsyncTx; + +static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; + +static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { + while (samples > 0) { + LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + if (level_duration_is_reset(ld)) { + break; + } else { + uint32_t duration = level_duration_get_duration(ld); + assert(duration > 0); + *buffer = duration; + } + buffer++; + samples--; + } + + memset(buffer, 0, samples * sizeof(uint32_t)); +} + +static void furi_hal_subghz_async_tx_dma_isr() { + furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx); + if (LL_DMA_IsActiveFlag_HT1(DMA1)) { + LL_DMA_ClearFlag_HT1(DMA1); + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); + } if (LL_DMA_IsActiveFlag_TC1(DMA1)) { LL_DMA_ClearFlag_TC1(DMA1); - furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx); - if (--furi_hal_subghz_tx_repeat == 0) { - furi_hal_subghz_state = SubGhzStateAsyncTxLast; - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - } + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer+API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); } } -static void furi_hal_subghz_tx_timer_isr() { +static void furi_hal_subghz_async_tx_timer_isr() { if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) { LL_TIM_ClearFlag_UPDATE(TIM2); - if (furi_hal_subghz_state == SubGhzStateAsyncTxLast) { - LL_TIM_DisableCounter(TIM2); - furi_hal_subghz_state = SubGhzStateAsyncTxEnd; + if (LL_TIM_GetAutoReload(TIM2) == 0) { + if (furi_hal_subghz_state == SubGhzStateAsyncTx) { + furi_hal_subghz_state = SubGhzStateAsyncTxLast; + } else { + furi_hal_subghz_state = SubGhzStateAsyncTxEnd; + LL_TIM_DisableCounter(TIM2); + hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullDown, GpioSpeedLow); + } } } } -void furi_hal_subghz_start_async_tx(uint32_t* buffer, size_t buffer_size, size_t repeat) { +void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context) { furi_assert(furi_hal_subghz_state == SubGhzStateIdle); + furi_assert(callback); + + furi_hal_subghz_async_tx.callback = callback; + furi_hal_subghz_async_tx.callback_context = context; + furi_hal_subghz_state = SubGhzStateAsyncTx; - furi_hal_subghz_tx_repeat = repeat; + + furi_hal_subghz_async_tx.buffer = furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); // Connect CC1101_GD0 to TIM2 as output hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); @@ -436,19 +476,20 @@ void furi_hal_subghz_start_async_tx(uint32_t* buffer, size_t buffer_size, size_t // Configure DMA LL_DMA_InitTypeDef dma_config = {0}; dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); - dma_config.MemoryOrM2MDstAddress = (uint32_t)buffer; + dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.NbData = buffer_size / sizeof(uint32_t); + dma_config.NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_MODE_NORMAL; LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); - furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_tx_dma_isr); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr); LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); // Configure TIM2 @@ -473,7 +514,7 @@ void furi_hal_subghz_start_async_tx(uint32_t* buffer, size_t buffer_size, size_t LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_DisableMasterSlaveMode(TIM2); - furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_tx_timer_isr); + furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_async_tx_timer_isr); LL_TIM_EnableIT_UPDATE(TIM2); LL_TIM_EnableDMAReq_UPDATE(TIM2); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); @@ -493,12 +534,8 @@ void furi_hal_subghz_start_async_tx(uint32_t* buffer, size_t buffer_size, size_t LL_TIM_EnableCounter(TIM2); } -size_t furi_hal_subghz_get_async_tx_repeat_left() { - return furi_hal_subghz_tx_repeat; -} - -void furi_hal_subghz_wait_async_tx() { - while(furi_hal_subghz_state != SubGhzStateAsyncTxEnd) osDelay(1); +bool furi_hal_subghz_is_async_tx_complete() { + return furi_hal_subghz_state == SubGhzStateAsyncTxEnd; } void furi_hal_subghz_stop_async_tx() { @@ -526,5 +563,7 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize GPIO hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + free(furi_hal_subghz_async_tx.buffer); + furi_hal_subghz_state = SubGhzStateIdle; } diff --git a/firmware/targets/furi-hal-include/furi-hal-subghz.h b/firmware/targets/furi-hal-include/furi-hal-subghz.h index 683bf709..bf80d7e1 100644 --- a/firmware/targets/furi-hal-include/furi-hal-subghz.h +++ b/firmware/targets/furi-hal-include/furi-hal-subghz.h @@ -132,35 +132,29 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path); /** Signal Timings Capture callback */ typedef void (*FuriHalSubGhzCaptureCallback)(bool level, uint32_t duration, void* context); -/** Set signal timings capture callback - * @param callback - your callback for front capture - */ -void furi_hal_subghz_set_async_rx_callback(FuriHalSubGhzCaptureCallback callback, void* context); - /** Enable signal timings capture * Initializes GPIO and TIM2 for timings capture */ -void furi_hal_subghz_start_async_rx(); +void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context); /** Disable signal timings capture * Resets GPIO and TIM2 */ void furi_hal_subghz_stop_async_rx(); -/** Send buffer - * Initializes GPIO, TIM2 and DMA1 for signal output - * @param buffer - pointer to data buffer - * @param buffer_size - buffer size in bytes +/** Async TX callback type + * @param context - callback context + * @return LevelDuration */ -void furi_hal_subghz_start_async_tx(uint32_t* buffer, size_t buffer_size, size_t repeat); +typedef LevelDuration (*FuriHalSubGhzAsyncTxCallback)(void* context); -/** Get repeats left count for async tx - * @return packets left to send +/** Start async TX + * Initializes GPIO, TIM2 and DMA1 for signal output */ -size_t furi_hal_subghz_get_async_tx_repeat_left(); +void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context); /** Wait for async transmission to complete */ -void furi_hal_subghz_wait_async_tx(); +bool furi_hal_subghz_is_async_tx_complete(); /** Stop async transmission and cleanup resources * Resets GPIO, TIM2, and DMA1 diff --git a/lib/subghz/protocols/subghz_protocol.c b/lib/subghz/protocols/subghz_protocol.c index 32e7dc05..f0b93066 100644 --- a/lib/subghz/protocols/subghz_protocol.c +++ b/lib/subghz/protocols/subghz_protocol.c @@ -16,19 +16,26 @@ #include #include +typedef enum { + SubGhzProtocolTypeCame, + SubGhzProtocolTypeKeeloq, + SubGhzProtocolTypeNiceFlo, + SubGhzProtocolTypeNiceFlorS, + SubGhzProtocolTypePrinceton, + SubGhzProtocolTypeGateTX, + SubGhzProtocolTypeIDo, + SubGhzProtocolTypeFaacSLH, + SubGhzProtocolTypeNeroSketch, + SubGhzProtocolTypeStarLine, + + SubGhzProtocolTypeMax, +} SubGhzProtocolType; + + struct SubGhzProtocol { SubGhzKeystore* keystore; - SubGhzProtocolCame* came; - SubGhzProtocolKeeloq* keeloq; - SubGhzProtocolNiceFlo* nice_flo; - SubGhzProtocolNiceFlorS* nice_flor_s; - SubGhzProtocolPrinceton* princeton; - SubGhzProtocolGateTX* gate_tx; - SubGhzProtocolIDo* ido; - SubGhzProtocolFaacSLH* faac_slh; - SubGhzProtocolNeroSketch* nero_sketch; - SubGhzProtocolStarLine* star_line; + SubGhzProtocolCommon* protocols[SubGhzProtocolTypeMax]; SubGhzProtocolTextCallback text_callback; void* text_callback_context; @@ -62,16 +69,16 @@ SubGhzProtocol* subghz_protocol_alloc() { instance->keystore = subghz_keystore_alloc(); - instance->came = subghz_protocol_came_alloc(); - instance->keeloq = subghz_protocol_keeloq_alloc(instance->keystore); - instance->princeton = subghz_protocol_princeton_alloc(); - instance->nice_flo = subghz_protocol_nice_flo_alloc(); - instance->nice_flor_s = subghz_protocol_nice_flor_s_alloc(); - instance->gate_tx = subghz_protocol_gate_tx_alloc(); - instance->ido = subghz_protocol_ido_alloc(); - instance->faac_slh = subghz_protocol_faac_slh_alloc(); - instance->nero_sketch = subghz_protocol_nero_sketch_alloc(); - instance->star_line = subghz_protocol_star_line_alloc(instance->keystore); + instance->protocols[SubGhzProtocolTypeCame] =(SubGhzProtocolCommon*)subghz_protocol_came_alloc(); + instance->protocols[SubGhzProtocolTypeKeeloq] = (SubGhzProtocolCommon*)subghz_protocol_keeloq_alloc(instance->keystore); + instance->protocols[SubGhzProtocolTypePrinceton] = (SubGhzProtocolCommon*)subghz_decoder_princeton_alloc(); + instance->protocols[SubGhzProtocolTypeNiceFlo] = (SubGhzProtocolCommon*)subghz_protocol_nice_flo_alloc(); + instance->protocols[SubGhzProtocolTypeNiceFlorS] = (SubGhzProtocolCommon*)subghz_protocol_nice_flor_s_alloc(); + instance->protocols[SubGhzProtocolTypeGateTX] = (SubGhzProtocolCommon*)subghz_protocol_gate_tx_alloc(); + instance->protocols[SubGhzProtocolTypeIDo] = (SubGhzProtocolCommon*)subghz_protocol_ido_alloc(); + instance->protocols[SubGhzProtocolTypeFaacSLH] = (SubGhzProtocolCommon*)subghz_protocol_faac_slh_alloc(); + instance->protocols[SubGhzProtocolTypeNeroSketch] = (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc(); + instance->protocols[SubGhzProtocolTypeStarLine] = (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore); return instance; } @@ -79,35 +86,41 @@ SubGhzProtocol* subghz_protocol_alloc() { void subghz_protocol_free(SubGhzProtocol* instance) { furi_assert(instance); - subghz_protocol_came_free(instance->came); - subghz_protocol_keeloq_free(instance->keeloq); - subghz_protocol_princeton_free(instance->princeton); - subghz_protocol_nice_flo_free(instance->nice_flo); - subghz_protocol_nice_flor_s_free(instance->nice_flor_s); - subghz_protocol_gate_tx_free(instance->gate_tx); - subghz_protocol_ido_free(instance->ido); - subghz_protocol_faac_slh_free(instance->faac_slh); - subghz_protocol_nero_sketch_free(instance->nero_sketch); - subghz_protocol_star_line_free(instance->star_line); + subghz_protocol_came_free((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]); + subghz_protocol_keeloq_free((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]); + subghz_decoder_princeton_free((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]); + subghz_protocol_nice_flo_free((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]); + subghz_protocol_nice_flor_s_free((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]); + subghz_protocol_gate_tx_free((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]); + subghz_protocol_ido_free((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo]); + subghz_protocol_faac_slh_free((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]); + subghz_protocol_nero_sketch_free((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); + subghz_protocol_star_line_free((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); subghz_keystore_free(instance->keystore); free(instance); } +SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, const char* name) { + SubGhzProtocolCommon* result = NULL; + + for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { + if(strcmp(instance->protocols[i]->name, name) == 0) { + result = instance->protocols[i]; + break; + } + } + + return result; +} + void subghz_protocol_enable_dump_text(SubGhzProtocol* instance, SubGhzProtocolTextCallback callback, void* context) { furi_assert(instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->keeloq, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->princeton, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flo, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flor_s, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->gate_tx, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->ido, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->faac_slh, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nero_sketch, subghz_protocol_text_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->star_line, subghz_protocol_text_rx_callback, instance); + for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { + subghz_protocol_common_set_callback(instance->protocols[i], subghz_protocol_text_rx_callback, instance); + } instance->text_callback = callback; instance->text_callback_context = context; @@ -116,24 +129,18 @@ void subghz_protocol_enable_dump_text(SubGhzProtocol* instance, SubGhzProtocolTe void subghz_protocol_enable_dump(SubGhzProtocol* instance, SubGhzProtocolCommonCallbackDump callback, void* context) { furi_assert(instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->keeloq, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->princeton, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flo, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flor_s, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->gate_tx, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->ido, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->faac_slh, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nero_sketch, subghz_protocol_parser_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->star_line, subghz_protocol_parser_rx_callback, instance); - + for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { + subghz_protocol_common_set_callback(instance->protocols[i], subghz_protocol_parser_rx_callback, instance); + } + instance->parser_callback = callback; instance->parser_callback_context = context; } void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { - subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name); + // subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name); + subghz_protocol_nice_flor_s_name_file((SubGhzProtocolNiceFlorS*) instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); } void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file_name) { @@ -141,27 +148,29 @@ void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file } void subghz_protocol_reset(SubGhzProtocol* instance) { - subghz_protocol_came_reset(instance->came); - subghz_protocol_keeloq_reset(instance->keeloq); - subghz_protocol_princeton_reset(instance->princeton); - subghz_protocol_nice_flo_reset(instance->nice_flo); - subghz_protocol_nice_flor_s_reset(instance->nice_flor_s); - subghz_protocol_gate_tx_reset(instance->gate_tx); - subghz_protocol_ido_reset(instance->ido); - subghz_protocol_faac_slh_reset(instance->faac_slh); - subghz_protocol_nero_sketch_reset(instance->nero_sketch); - subghz_protocol_star_line_reset(instance->star_line); + + subghz_protocol_came_reset((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]); + subghz_protocol_keeloq_reset((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]); + subghz_decoder_princeton_reset((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]); + subghz_protocol_nice_flo_reset((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]); + subghz_protocol_nice_flor_s_reset((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]); + subghz_protocol_gate_tx_reset((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]); + subghz_protocol_ido_reset((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo]); + subghz_protocol_faac_slh_reset((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]); + subghz_protocol_nero_sketch_reset((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); + subghz_protocol_star_line_reset((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); } void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { - subghz_protocol_came_parse(instance->came, level, duration); - subghz_protocol_keeloq_parse(instance->keeloq, level, duration); - subghz_protocol_princeton_parse(instance->princeton, level, duration); - subghz_protocol_nice_flo_parse(instance->nice_flo, level, duration); - subghz_protocol_nice_flor_s_parse(instance->nice_flor_s, level, duration); - subghz_protocol_gate_tx_parse(instance->gate_tx, level, duration); - subghz_protocol_ido_parse(instance->ido, level, duration); - subghz_protocol_faac_slh_parse(instance->faac_slh, level, duration); - subghz_protocol_nero_sketch_parse(instance->nero_sketch, level, duration); - subghz_protocol_star_line_parse(instance->star_line, level, duration); + + subghz_protocol_came_parse((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame], level, duration); + subghz_protocol_keeloq_parse((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq], level, duration); + subghz_decoder_princeton_parse((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton], level, duration); + subghz_protocol_nice_flo_parse((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo], level, duration); + subghz_protocol_nice_flor_s_parse((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], level, duration); + subghz_protocol_gate_tx_parse((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX], level, duration); + subghz_protocol_ido_parse((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo], level, duration); + subghz_protocol_faac_slh_parse((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH], level, duration); + subghz_protocol_nero_sketch_parse((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch], level, duration); + subghz_protocol_star_line_parse((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration); } diff --git a/lib/subghz/protocols/subghz_protocol.h b/lib/subghz/protocols/subghz_protocol.h index 33592854..3c33b814 100644 --- a/lib/subghz/protocols/subghz_protocol.h +++ b/lib/subghz/protocols/subghz_protocol.h @@ -19,6 +19,14 @@ SubGhzProtocol* subghz_protocol_alloc(); */ void subghz_protocol_free(SubGhzProtocol* instance); +/** Get protocol by name + * + * @param instance - SubGhzProtocol instance + * @param name - name protocol + * @param SubGhzProtocolCommon + */ +SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, const char* name); + /** Outputting data text from all parsers * * @param instance - SubGhzProtocol instance diff --git a/lib/subghz/protocols/subghz_protocol_came.c b/lib/subghz/protocols/subghz_protocol_came.c index 68f78576..7af2f6dc 100644 --- a/lib/subghz/protocols/subghz_protocol_came.c +++ b/lib/subghz/protocols/subghz_protocol_came.c @@ -19,6 +19,11 @@ SubGhzProtocolCame* subghz_protocol_came_alloc() { instance->common.te_shot = 320; instance->common.te_long = 640; instance->common.te_delta = 150; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_protocol_came_to_save_str; + instance->common.to_load_protocol= + (SubGhzProtocolCommonLoad)subghz_protocol_came_to_load_protocol; return instance; } @@ -99,6 +104,10 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32 instance->common.serial = 0x0; instance->common.btn = 0x0; + + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); @@ -129,3 +138,75 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32 break; } } + +void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + uint64_t code_found_reverse = subghz_protocol_common_reverse_key( + instance->common.code_last_found, instance->common.code_last_count_bit); + + uint32_t code_found_reverse_hi = code_found_reverse >> 32; + uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + + string_cat_printf( + output, + "%s %d Bit\r\n" + " KEY:0x%lX%08lX\r\n" + " YEK:0x%lX%08lX\r\n", + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + code_found_reverse_lo + ); +} + +void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output) { + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Key: %08lX\n", + instance->common.name, + instance->common.code_last_count_bit, + (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); +} + +bool subghz_protocol_came_to_load_protocol(FileWorker* file_worker, SubGhzProtocolCame* instance){ + bool loaded = false; + string_t temp_str; + string_init(temp_str); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse key data from 3nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + uint32_t temp_key = 0; + res = sscanf(string_get_cstr(temp_str), "Key: %08lX\n", &temp_key); + if(res != 1) { + break; + } + instance->common.code_last_found = (uint64_t)temp_key; + + loaded = true; + } while(0); + + string_clear(temp_str); + + return loaded; +} diff --git a/lib/subghz/protocols/subghz_protocol_came.h b/lib/subghz/protocols/subghz_protocol_came.h index 7ce1aa09..42c1b9a3 100644 --- a/lib/subghz/protocols/subghz_protocol_came.h +++ b/lib/subghz/protocols/subghz_protocol_came.h @@ -36,3 +36,13 @@ void subghz_protocol_came_reset(SubGhzProtocolCame* instance); * @param data - LevelDuration level_duration */ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolCame* instance + * @param output - output string + */ +void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output); + +void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output); +bool subghz_protocol_came_to_load_protocol(FileWorker* file_worker, SubGhzProtocolCame* instance); diff --git a/lib/subghz/protocols/subghz_protocol_common.h b/lib/subghz/protocols/subghz_protocol_common.h index 298bdeb7..a00b0aba 100644 --- a/lib/subghz/protocols/subghz_protocol_common.h +++ b/lib/subghz/protocols/subghz_protocol_common.h @@ -3,37 +3,50 @@ #include #include #include +#include "file-worker.h" #define bit_read(value, bit) (((value) >> (bit)) & 0x01) #define bit_set(value, bit) ((value) |= (1UL << (bit))) #define bit_clear(value, bit) ((value) &= ~(1UL << (bit))) #define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) -#define SUBGHZ_TX_PIN_HIGTH() -#define SUBGHZ_TX_PIN_LOW() +#define SUBGHZ_TX_PIN_HIGTH() +#define SUBGHZ_TX_PIN_LOW() #define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y)) +//#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz/saved" +#define SUBGHZ_APP_FOLDER "/any/subghz" +#define SUBGHZ_APP_PATH_FOLDER "/any/subghz/saved" +#define SUBGHZ_APP_EXTENSION ".sub" + typedef struct SubGhzProtocolCommon SubGhzProtocolCommon; typedef void (*SubGhzProtocolCommonCallback)(SubGhzProtocolCommon* parser, void* context); typedef void (*SubGhzProtocolCommonToStr)(SubGhzProtocolCommon* instance, string_t output); +//Save +typedef void (*SubGhzProtocolCommonGetStrSave)(SubGhzProtocolCommon* instance, string_t output); + +//Load +typedef bool (*SubGhzProtocolCommonLoad)(FileWorker* file_worker, SubGhzProtocolCommon* instance); + struct SubGhzProtocolCommon { const char* name; - uint16_t te_long; - uint16_t te_shot; - uint16_t te_delta; - uint64_t code_found; - uint64_t code_last_found; - uint8_t code_count_bit; - uint8_t code_min_count_bit_for_found; - uint8_t parser_step; - uint32_t te_last; - uint8_t header_count; - uint16_t cnt; - uint32_t serial; - uint8_t btn; + uint16_t te_long; + uint16_t te_shot; + uint16_t te_delta; + uint8_t code_count_bit; + uint8_t code_last_count_bit; + uint64_t code_found; + uint64_t code_last_found; + uint8_t code_min_count_bit_for_found; + uint8_t parser_step; + uint32_t te_last; + uint8_t header_count; + uint16_t cnt; + uint32_t serial; + uint8_t btn; /* Standard Callback for on rx complete event */ SubGhzProtocolCommonCallback callback; @@ -41,15 +54,18 @@ struct SubGhzProtocolCommon { /* Dump To String */ SubGhzProtocolCommonToStr to_string; + /* Get string to save */ + SubGhzProtocolCommonGetStrSave to_save_string; + /*Load protocol by file*/ + SubGhzProtocolCommonLoad to_load_protocol; }; - /** Add data bit to code_found * * @param common - SubGhzProtocolCommon common * @param bit - add bit */ -void subghz_protocol_common_add_bit(SubGhzProtocolCommon *common, uint8_t bit); +void subghz_protocol_common_add_bit(SubGhzProtocolCommon* common, uint8_t bit); /** Checking that the duration is included in the interval * @@ -58,7 +74,10 @@ void subghz_protocol_common_add_bit(SubGhzProtocolCommon *common, uint8_t bit); * @param duration_check duration checked * @return true on success */ -bool subghz_protocol_common_check_interval(SubGhzProtocolCommon *common, uint32_t duration, uint16_t duration_check); +bool subghz_protocol_common_check_interval( + SubGhzProtocolCommon* common, + uint32_t duration, + uint16_t duration_check); /** Bit-by-bit data mirroring * @@ -68,14 +87,16 @@ bool subghz_protocol_common_check_interval(SubGhzProtocolCommon *common, uint32_ */ uint64_t subghz_protocol_common_reverse_key(uint64_t key, uint8_t count_bit); - /** Callback protocol * * @param instance - SubGhzProtocolCommon* instance * @param callback * @param context */ -void subghz_protocol_common_set_callback(SubGhzProtocolCommon* instance, SubGhzProtocolCommonCallback callback, void* context); +void subghz_protocol_common_set_callback( + SubGhzProtocolCommon* instance, + SubGhzProtocolCommonCallback callback, + void* context); /** outputting information from the parser * @@ -83,4 +104,3 @@ void subghz_protocol_common_set_callback(SubGhzProtocolCommon* instance, SubGhzP * @param output - output string */ void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output); - diff --git a/lib/subghz/protocols/subghz_protocol_gate_tx.c b/lib/subghz/protocols/subghz_protocol_gate_tx.c index 90fa0521..cfd01db0 100644 --- a/lib/subghz/protocols/subghz_protocol_gate_tx.c +++ b/lib/subghz/protocols/subghz_protocol_gate_tx.c @@ -14,6 +14,10 @@ SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) { instance->common.te_long = 700; instance->common.te_delta = 100; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_gate_tx_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_protocol_gate_tx_to_save_str; + instance->common.to_load_protocol= + (SubGhzProtocolCommonLoad)subghz_protocol_gate_tx_to_load_protocol; return instance; } @@ -68,13 +72,10 @@ void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance) { * @param instance SubGhzProtocolFaacSLH instance */ void subghz_protocol_gate_tx_check_remote_controller(SubGhzProtocolGateTX* instance) { - uint32_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + uint32_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); instance->common.serial = (code_found_reverse & 0xFF) << 12 | ((code_found_reverse >>8) & 0xFF) << 4 | ((code_found_reverse >>20) & 0x0F) ; instance->common.btn = ((code_found_reverse >> 16) & 0x0F); - - if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); - } void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, uint32_t duration) { @@ -103,7 +104,11 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u if (duration >= (instance->common.te_shot * 10 + instance->common.te_delta)) { instance->common.parser_step = 1; if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { - subghz_protocol_gate_tx_check_remote_controller(instance); + + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + + if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); } instance->common.code_found = 0; instance->common.code_count_bit = 0; @@ -135,20 +140,64 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u } void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output) { - - // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); - // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; - // uint32_t code_hop = (code_found_reverse >>32) & 0xFFFFFFFF; - - //uint32_t rev_hi = - + subghz_protocol_gate_tx_check_remote_controller(instance); string_cat_printf(output, - "Protocol %s, %d Bit\r\n" + "%s, %d Bit\r\n" " KEY:%06lX\r\n" " SN:%05lX BTN:%lX\r\n", instance->common.name, - instance->common.code_count_bit, - (uint32_t)(instance->common.code_found & 0xFFFFFF), + instance->common.code_last_count_bit, + (uint32_t)(instance->common.code_last_found & 0xFFFFFF), instance->common.serial, - instance->common.btn); -} \ No newline at end of file + instance->common.btn + ); +} + +void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output) { + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Key: %08lX\n", + instance->common.name, + instance->common.code_last_count_bit, + (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); +} + +bool subghz_protocol_gate_tx_to_load_protocol(FileWorker* file_worker, SubGhzProtocolGateTX* instance){ + bool loaded = false; + string_t temp_str; + string_init(temp_str); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse key data from 3nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + uint32_t temp_key = 0; + res = sscanf(string_get_cstr(temp_str), "Key: %08lX\n", &temp_key); + if(res != 1) { + break; + } + instance->common.code_last_found = (uint64_t)temp_key; + subghz_protocol_gate_tx_check_remote_controller(instance); + + loaded = true; + } while(0); + + string_clear(temp_str); + + return loaded; +} diff --git a/lib/subghz/protocols/subghz_protocol_gate_tx.h b/lib/subghz/protocols/subghz_protocol_gate_tx.h index 3e73da92..c02a8c45 100644 --- a/lib/subghz/protocols/subghz_protocol_gate_tx.h +++ b/lib/subghz/protocols/subghz_protocol_gate_tx.h @@ -42,4 +42,7 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u * @param instance - SubGhzProtocolFaacSLH* instance * @param output - output string */ -void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output); \ No newline at end of file +void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output); + +void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output); +bool subghz_protocol_gate_tx_to_load_protocol(FileWorker* file_worker, SubGhzProtocolGateTX* instance); diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 28a7a053..878e17bc 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -24,6 +24,10 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) { instance->common.te_long = 800; instance->common.te_delta = 140; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_protocol_keeloq_to_save_str; + instance->common.to_load_protocol = + (SubGhzProtocolCommonLoad)subghz_protocol_keeloq_to_load_protocol; return instance; } @@ -40,86 +44,97 @@ void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance) { * @param hop hop encrypted part of the parcel * @return true on successful search */ -uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKeeloq* instance, uint32_t fix , uint32_t hop) { - uint16_t end_serial = (uint16_t)(fix&0x3FF); - uint8_t btn = (uint8_t)(fix>>28); +uint8_t subghz_protocol_keeloq_check_remote_controller_selector( + SubGhzProtocolKeeloq* instance, + uint32_t fix, + uint32_t hop) { + uint16_t end_serial = (uint16_t)(fix & 0x3FF); + uint8_t btn = (uint8_t)(fix >> 28); uint32_t decrypt = 0; uint64_t man_normal_learning; for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { - switch (manufacture_code->type){ - case KEELOQ_LEARNING_SIMPLE: - //Simple Learning - decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - if((decrypt>>28 == btn) && ((((uint16_t)(decrypt>>16)) & 0x3FF) == end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt = decrypt & 0x0000FFFF; - return 1; - } + switch(manufacture_code->type) { + case KEELOQ_LEARNING_SIMPLE: + //Simple Learning + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } break; - case KEELOQ_LEARNING_NORMAL: - // Normal_Learning - // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); - decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if( (decrypt>>28 ==btn)&& ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt = decrypt & 0x0000FFFF; - return 1; - } + case KEELOQ_LEARNING_NORMAL: + // Normal_Learning + // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 + man_normal_learning = + subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } break; - case KEELOQ_LEARNING_UNKNOWN: - // Simple Learning - decrypt=subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt = decrypt & 0x0000FFFF; - return 1; - } - // Check for mirrored man - uint64_t man_rev=0; - uint64_t man_rev_byte=0; - for(uint8_t i=0; i<64; i+=8){ - man_rev_byte=(uint8_t)(manufacture_code->key >> i); - man_rev = man_rev | man_rev_byte << (56-i); - } - decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_rev); - if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt= decrypt&0x0000FFFF; - return 1; - } - //########################### - // Normal_Learning - // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); - decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if( (decrypt>>28 ==btn)&& ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt= decrypt&0x0000FFFF; - return 1; - } - // Check for mirrored man - man_rev=0; - man_rev_byte=0; - for(uint8_t i=0; i<64; i+=8){ - man_rev_byte = (uint8_t)(manufacture_code->key >> i); - man_rev = man_rev | man_rev_byte << (56-i); - } - man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); - decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); - if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ - instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt= decrypt&0x0000FFFF; - return 1; - } + case KEELOQ_LEARNING_UNKNOWN: + // Simple Learning + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + // Check for mirrored man + uint64_t man_rev = 0; + uint64_t man_rev_byte = 0; + for(uint8_t i = 0; i < 64; i += 8) { + man_rev_byte = (uint8_t)(manufacture_code->key >> i); + man_rev = man_rev | man_rev_byte << (56 - i); + } + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + //########################### + // Normal_Learning + // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 + man_normal_learning = + subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + // Check for mirrored man + man_rev = 0; + man_rev_byte = 0; + for(uint8_t i = 0; i < 64; i += 8) { + man_rev_byte = (uint8_t)(manufacture_code->key >> i); + man_rev = man_rev | man_rev_byte << (56 - i); + } + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if((decrypt >> 28 == btn) && + ((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } break; } } instance->manufacture_name = "Unknown"; - instance->common.cnt=0; + instance->common.cnt = 0; return 0; } @@ -129,22 +144,23 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe * @param instance SubGhzProtocolKeeloq instance */ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instance) { - uint64_t key = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + uint64_t key = subghz_protocol_common_reverse_key( + instance->common.code_last_found, instance->common.code_last_count_bit); uint32_t key_fix = key >> 32; uint32_t key_hop = key & 0x00000000ffffffff; // Check key AN-Motors - if((key_hop >> 24) == ((key_hop>>16)&0x00ff) && (key_fix>>28) ==((key_hop>>12)&0x0f) && (key_hop & 0xFFF ) == 0x404){ + if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && + (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { instance->manufacture_name = "AN-Motors"; - instance->common.cnt = key_hop>>16; - } else if((key_hop & 0xFFF) == (0x000) && (key_fix>>28) ==((key_hop>>12)&0x0f) ){ + instance->common.cnt = key_hop >> 16; + } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { instance->manufacture_name = "HCS101"; - instance->common.cnt = key_hop>>16; + instance->common.cnt = key_hop >> 16; } else { subghz_protocol_keeloq_check_remote_controller_selector(instance, key_fix, key_hop); } - instance ->common.serial= key_fix&0x0FFFFFFF; + instance->common.serial = key_fix & 0x0FFFFFFF; instance->common.btn = key_fix >> 28; - if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); } /** Send bit @@ -153,7 +169,7 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan * @param bit - bit */ void subghz_protocol_keeloq_send_bit(SubGhzProtocolKeeloq* instance, uint8_t bit) { - if (bit) { + if(bit) { // send bit 1 SUBGHZ_TX_PIN_HIGTH(); delay_us(instance->common.te_shot); @@ -168,10 +184,14 @@ void subghz_protocol_keeloq_send_bit(SubGhzProtocolKeeloq* instance, uint8_t bit } } -void subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, uint64_t key, uint8_t bit, uint8_t repeat) { - while (repeat--) { +void subghz_protocol_keeloq_send_key( + SubGhzProtocolKeeloq* instance, + uint64_t key, + uint8_t bit, + uint8_t repeat) { + while(repeat--) { // Send header - for (uint8_t i = 11; i > 0; i--) { + for(uint8_t i = 11; i > 0; i--) { SUBGHZ_TX_PIN_HIGTH(); delay_us(instance->common.te_shot); SUBGHZ_TX_PIN_LOW(); @@ -179,7 +199,7 @@ void subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, uint64_t ke } delay_us(instance->common.te_shot * 9); //+1 up Send header - for (uint8_t i = bit; i > 0; i--) { + for(uint8_t i = bit; i > 0; i--) { subghz_protocol_keeloq_send_bit(instance, bit_read(key, i - 1)); } // +send 2 status bit @@ -187,7 +207,7 @@ void subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, uint64_t ke subghz_protocol_keeloq_send_bit(instance, 0); // send end subghz_protocol_keeloq_send_bit(instance, 0); - delay_us(instance->common.te_shot * 2); //+2 interval END SEND + delay_us(instance->common.te_shot * 2); //+2 interval END SEND } } @@ -196,9 +216,10 @@ void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) { } void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration) { - switch (instance->common.parser_step) { + switch(instance->common.parser_step) { case 0: - if ((level) && DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta) { + if((level) && + DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta) { instance->common.parser_step = 1; instance->common.header_count++; } else { @@ -207,11 +228,14 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui break; case 1: - if ((!level) && (DURATION_DIFF(duration, instance->common.te_shot ) < instance->common.te_delta)) { + if((!level) && + (DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { instance->common.parser_step = 0; break; } - if ((instance->common.header_count > 2) && ( DURATION_DIFF(duration, instance->common.te_shot * 10)< instance->common.te_delta * 10)) { + if((instance->common.header_count > 2) && + (DURATION_DIFF(duration, instance->common.te_shot * 10) < + instance->common.te_delta * 10)) { // Found header instance->common.parser_step = 2; instance->common.code_found = 0; @@ -222,35 +246,45 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui } break; case 2: - if (level) { + if(level) { instance->common.te_last = duration; instance->common.parser_step = 3; } break; case 3: - if (!level) { - if (duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) { + if(!level) { + if(duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) { // Found end TX instance->common.parser_step = 0; - if (instance->common.code_count_bit >= instance->common.code_min_count_bit_for_found) { - if(instance->common.code_last_found != instance->common.code_found ){ - subghz_protocol_keeloq_check_remote_controller(instance); + if(instance->common.code_count_bit >= + instance->common.code_min_count_bit_for_found) { + if(instance->common.code_last_found != instance->common.code_found) { + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + if(instance->common.callback) + instance->common.callback( + (SubGhzProtocolCommon*)instance, instance->common.context); } - instance->common.code_last_found = instance->common.code_found; instance->common.code_found = 0; instance->common.code_count_bit = 0; instance->common.header_count = 0; } break; - } else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < instance->common.te_delta) - && (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { - if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) { + } else if( + (DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < + instance->common.te_delta) && + (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { + if(instance->common.code_count_bit < + instance->common.code_min_count_bit_for_found) { subghz_protocol_common_add_bit(&instance->common, 1); } instance->common.parser_step = 2; - } else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_long) < instance->common.te_delta) - && (DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { - if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) { + } else if( + (DURATION_DIFF(instance->common.te_last, instance->common.te_long) < + instance->common.te_delta) && + (DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { + if(instance->common.code_count_bit < + instance->common.code_min_count_bit_for_found) { subghz_protocol_common_add_bit(&instance->common, 0); } instance->common.parser_step = 2; @@ -267,29 +301,152 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui } void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output) { - uint32_t code_found_hi = instance->common.code_found >> 32; - uint32_t code_found_lo = instance->common.code_found & 0x00000000ffffffff; + subghz_protocol_keeloq_check_remote_controller(instance); + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; - uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + uint64_t code_found_reverse = subghz_protocol_common_reverse_key( + instance->common.code_last_found, instance->common.code_last_count_bit); - uint32_t code_found_reverse_hi = code_found_reverse>>32; - uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff; + uint32_t code_found_reverse_hi = code_found_reverse >> 32; + uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; string_cat_printf( output, - "Protocol %s, %d Bit\r\n" + "%s, %d Bit\r\n" "KEY:0x%lX%lX\r\n" "FIX:%08lX MF:%s \r\n" "HOP:%08lX \r\n" "SN:%07lX CNT:%04X B:%02lX\r\n", instance->common.name, - instance->common.code_count_bit, + instance->common.code_last_count_bit, code_found_hi, code_found_lo, code_found_reverse_hi, instance->manufacture_name, code_found_reverse_lo, instance->common.serial, - instance->common.cnt, - instance->common.btn - ); + instance->common.cnt, + instance->common.btn); +} + +uint64_t subghz_protocol_keeloq_gen_key(SubGhzProtocolKeeloq* instance) { + uint32_t fix = instance->common.btn << 28 | instance->common.serial; + uint32_t decrypt = instance->common.btn << 28 | (instance->common.serial & 0x3FF) << 16 | + instance->common.cnt; + uint32_t hop = 0; + uint64_t man_normal_learning = 0; + int res = 0; + + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name); + if(res == 0) { + switch(manufacture_code->type) { + case KEELOQ_LEARNING_SIMPLE: + //Simple Learning + hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key); + break; + case KEELOQ_LEARNING_NORMAL: + //Simple Learning + man_normal_learning = + subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + hop = subghz_protocol_keeloq_common_encrypt(decrypt, man_normal_learning); + break; + case KEELOQ_LEARNING_UNKNOWN: + hop = 0; //todo + break; + } + break; + } + } + uint64_t yek = (uint64_t)fix << 32 | hop; + return subghz_protocol_common_reverse_key(yek, instance->common.code_last_count_bit); +} + +void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) { + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Manufacture_name: %s\n" + "Serial: %08lX\n" + "Cnt: %04lX\n" + "Btn: %01lX\n", + instance->common.name, + instance->common.code_last_count_bit, + instance->manufacture_name, + instance->common.serial, + instance->common.cnt, + instance->common.btn); +} + +bool subghz_protocol_keeloq_to_load_protocol( + FileWorker* file_worker, + SubGhzProtocolKeeloq* instance) { + bool loaded = false; + string_t temp_str; + string_init(temp_str); + string_t temp_name_man; + string_init(temp_name_man); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse name protocol from 3st line + if(!file_worker_read_until(file_worker, temp_name_man, '\n')) { + break; + } + // strlen("Manufacture_name: ") = 18 + string_right(temp_name_man, 18); + instance->manufacture_name = string_get_cstr(temp_name_man); + + // Read and parse key data from 4nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + uint32_t temp_param = 0; + res = sscanf(string_get_cstr(temp_str), "Serial: %08lX\n", &temp_param); + if(res != 1) { + break; + } + instance->common.serial = temp_param; + + // Read and parse key data from 5nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Cnt: %04lX\n", &temp_param); + if(res != 1) { + break; + } + instance->common.cnt = (uint16_t)temp_param; + + // Read and parse key data from 5nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Btn: %01lX\n", &temp_param); + if(res != 1) { + break; + } + instance->common.btn = (uint8_t)temp_param; + + instance->common.code_last_found = subghz_protocol_keeloq_gen_key(instance); + + loaded = true; + } while(0); + string_clear(temp_name_man); + string_clear(temp_str); + + return loaded; } diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.h b/lib/subghz/protocols/subghz_protocol_keeloq.h index 298a6e97..4560c725 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq.h @@ -45,3 +45,6 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui * @param output - output string */ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output); + +void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output); +bool subghz_protocol_keeloq_to_load_protocol(FileWorker* file_worker, SubGhzProtocolKeeloq* instance); diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.h b/lib/subghz/protocols/subghz_protocol_keeloq_common.h index 109df6cd..33b9021e 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.h @@ -1,5 +1,7 @@ #pragma once #include "subghz_protocol_common.h" +#include "file-worker.h" + #include diff --git a/lib/subghz/protocols/subghz_protocol_nero_sketch.c b/lib/subghz/protocols/subghz_protocol_nero_sketch.c index 5f9f6a51..8e22b0f3 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_sketch.c +++ b/lib/subghz/protocols/subghz_protocol_nero_sketch.c @@ -14,6 +14,10 @@ SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc(void) { instance->common.te_long = 660; instance->common.te_delta = 150; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_sketch_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_sketch_to_save_str; + instance->common.to_load_protocol= + (SubGhzProtocolCommonLoad)subghz_protocol_nero_sketch_to_load_protocol; return instance; } @@ -80,18 +84,18 @@ void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance) { * * @param instance SubGhzProtocolNeroSketch instance */ -void subghz_protocol_nero_sketch_check_remote_controller(SubGhzProtocolNeroSketch* instance) { - //пока не понятно с серийником, но код статический - // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); - // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; - // //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF; +// void subghz_protocol_nero_sketch_check_remote_controller(SubGhzProtocolNeroSketch* instance) { +// //пока не понятно с серийником, но код статический +// // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); +// // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; +// // //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF; - // instance->common.serial = code_fix & 0xFFFFFFF; - // instance->common.btn = (code_fix >> 28) & 0x0F; +// // instance->common.serial = code_fix & 0xFFFFFFF; +// // instance->common.btn = (code_fix >> 28) & 0x0F; - if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); +// //if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); -} +// } void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool level, uint32_t duration) { switch (instance->common.parser_step) { @@ -140,7 +144,11 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool //Found stop bit instance->common.parser_step = 0; if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { - subghz_protocol_nero_sketch_check_remote_controller(instance); + + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + } instance->common.code_found = 0; instance->common.code_count_bit = 0; @@ -176,25 +184,77 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output) { - uint32_t code_found_hi = instance->common.code_found >> 32; - uint32_t code_found_lo = instance->common.code_found & 0x00000000ffffffff; + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; - uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint32_t code_found_reverse_hi = code_found_reverse>>32; uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff; - //uint32_t rev_hi = - string_cat_printf(output, - "Protocol %s, %d Bit\r\n" + "%s, %d Bit\r\n" " KEY:0x%lX%08lX\r\n" " YEK:0x%lX%08lX\r\n", instance->common.name, - instance->common.code_count_bit, + instance->common.code_last_count_bit, code_found_hi, code_found_lo, code_found_reverse_hi, code_found_reverse_lo ); } + +void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Key: %08lX%08lX\n", + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo + ); +} + +bool subghz_protocol_nero_sketch_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance){ + bool loaded = false; + string_t temp_str; + string_init(temp_str); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse key data from 3nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + uint32_t temp_key_hi = 0; + uint32_t temp_key_lo = 0; + res = sscanf(string_get_cstr(temp_str), "Key: %08lX%08lX\n", &temp_key_hi, &temp_key_lo); + if(res != 2) { + break; + } + instance->common.code_last_found = (uint64_t)temp_key_hi<<32 | temp_key_lo; + + loaded = true; + } while(0); + + string_clear(temp_str); + + return loaded; +} diff --git a/lib/subghz/protocols/subghz_protocol_nero_sketch.h b/lib/subghz/protocols/subghz_protocol_nero_sketch.h index 99d5dbca..4fcce1c2 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_sketch.h +++ b/lib/subghz/protocols/subghz_protocol_nero_sketch.h @@ -49,3 +49,6 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool * @param output - output string */ void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output); + +void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output); +bool subghz_protocol_nero_sketch_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance); diff --git a/lib/subghz/protocols/subghz_protocol_princeton.c b/lib/subghz/protocols/subghz_protocol_princeton.c index c2817e08..210f0db0 100644 --- a/lib/subghz/protocols/subghz_protocol_princeton.c +++ b/lib/subghz/protocols/subghz_protocol_princeton.c @@ -1,39 +1,120 @@ #include "subghz_protocol_princeton.h" - /* * Help * https://phreakerclub.com/447 * */ -struct SubGhzProtocolPrinceton { - SubGhzProtocolCommon common; +#define SUBGHZ_PT_SHORT 450 +#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3) +#define SUBGHZ_PT_GUARD (SUBGHZ_PT_SHORT * 30) + +struct SubGhzEncoderPrinceton { + uint32_t key; + uint16_t te; + size_t repeat; + size_t front; }; -SubGhzProtocolPrinceton* subghz_protocol_princeton_alloc(void) { - SubGhzProtocolPrinceton* instance = furi_alloc(sizeof(SubGhzProtocolPrinceton)); +struct SubGhzDecoderPrinceton { + SubGhzProtocolCommon common; + uint16_t te; +}; - instance->common.name = "Princeton"; - instance->common.code_min_count_bit_for_found = 24; - instance->common.te_shot = 450;//150; - instance->common.te_long = 1350;//450; - instance->common.te_delta = 200;//50; +SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc() { + SubGhzEncoderPrinceton* instance = furi_alloc(sizeof(SubGhzEncoderPrinceton)); + return instance; } -void subghz_protocol_princeton_free(SubGhzProtocolPrinceton* instance) { +void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance) { + furi_assert(instance); + free(instance); +} +void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder){ + SubGhzDecoderPrinceton* pricenton = decoder; + if((pricenton->te) !=0){ + instance->te = pricenton->te; + }else{ + instance->te = SUBGHZ_PT_SHORT; + } +} + + +void subghz_encoder_princeton_reset(SubGhzEncoderPrinceton* instance, uint32_t key, size_t repeat) { + furi_assert(instance); + instance->te = SUBGHZ_PT_SHORT; + instance->key = key; + instance->repeat = repeat; + instance->front = 48; +} + +size_t subghz_encoder_princeton_get_repeat_left(SubGhzEncoderPrinceton* instance) { + furi_assert(instance); + return instance->repeat; +} + +LevelDuration subghz_encoder_princeton_yield(void* context) { + SubGhzEncoderPrinceton* instance = context; + if(instance->repeat == 0) return level_duration_reset(); + + size_t bit = instance->front / 2; + bool level = !(instance->front % 2); + + LevelDuration ret; + if(bit < 24) { + uint8_t byte = bit / 8; + uint8_t bit_in_byte = bit % 8; + bool value = (((uint8_t*)&instance->key)[2 - byte] >> (7 - bit_in_byte)) & 1; + if(value) { + ret = level_duration_make(level, level ? instance->te * 3 : instance->te); + } else { + ret = level_duration_make(level, level ? instance->te : instance->te * 3); + } + } else { + ret = level_duration_make(level, level ? instance->te : instance->te * 30); + } + + instance->front++; + if(instance->front == 50) { + instance->repeat--; + instance->front = 0; + } + + return ret; +} + + +SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(void) { + SubGhzDecoderPrinceton* instance = furi_alloc(sizeof(SubGhzDecoderPrinceton)); + + instance->common.name = "Princeton"; + instance->common.code_min_count_bit_for_found = 24; + instance->common.te_shot = 450; //150; + instance->common.te_long = 1350; //450; + instance->common.te_delta = 200; //50; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_decoder_princeton_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_decoder_princeton_to_save_str; + instance->common.to_load_protocol= + (SubGhzProtocolCommonLoad)subghz_decoder_princeton_to_load_protocol; + + return instance; +} + +void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance) { furi_assert(instance); free(instance); } /** Send bit * - * @param instance - SubGhzProtocolPrinceton instance + * @param instance - SubGhzDecoderPrinceton instance * @param bit - bit */ -void subghz_protocol_princeton_send_bit(SubGhzProtocolPrinceton* instance, uint8_t bit) { - if (bit) { +void subghz_decoder_princeton_send_bit(SubGhzDecoderPrinceton* instance, uint8_t bit) { + if(bit) { //send bit 1 SUBGHZ_TX_PIN_LOW(); delay_us(instance->common.te_long); @@ -48,29 +129,36 @@ void subghz_protocol_princeton_send_bit(SubGhzProtocolPrinceton* instance, uint8 } } -void subghz_protocol_princeton_send_key(SubGhzProtocolPrinceton* instance, uint64_t key, uint8_t bit,uint8_t repeat) { - while (repeat--) { +void subghz_decoder_princeton_send_key( + SubGhzDecoderPrinceton* instance, + uint64_t key, + uint8_t bit, + uint8_t repeat) { + while(repeat--) { SUBGHZ_TX_PIN_LOW(); //Send start bit - subghz_protocol_princeton_send_bit(instance, 1); + subghz_decoder_princeton_send_bit(instance, 1); //Send header delay_us(instance->common.te_shot * 33); //+2 interval v bit 1 //Send key data - for (uint8_t i = bit; i > 0; i--) { - subghz_protocol_princeton_send_bit(instance, bit_read(key, i - 1)); + for(uint8_t i = bit; i > 0; i--) { + subghz_decoder_princeton_send_bit(instance, bit_read(key, i - 1)); } } } -void subghz_protocol_princeton_reset(SubGhzProtocolPrinceton* instance) { +void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance) { instance->common.parser_step = 0; } -void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool level, uint32_t duration) { - switch (instance->common.parser_step) { +void subghz_decoder_princeton_parse( + SubGhzDecoderPrinceton* instance, + bool level, + uint32_t duration) { + switch(instance->common.parser_step) { case 0: - if ((!level) - && (DURATION_DIFF(duration,instance->common.te_shot * 36) < instance->common.te_delta * 36)) { + if((!level) && (DURATION_DIFF(duration, instance->common.te_shot * 36) < + instance->common.te_delta * 36)) { //Found Preambula instance->common.parser_step = 1; instance->common.code_found = 0; @@ -81,33 +169,49 @@ void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool lev break; case 1: //save duration - if (level) { + if(level) { instance->common.te_last = duration; instance->common.parser_step = 2; } break; case 2: - if (!level) { - if (duration >= (instance->common.te_shot * 10 + instance->common.te_delta)) { + if(!level) { + if(duration >= (instance->common.te_shot * 10 + instance->common.te_delta)) { instance->common.parser_step = 1; - if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { + if(instance->common.code_count_bit >= + instance->common.code_min_count_bit_for_found) { + if(instance->common.code_last_found == instance->common.code_found) { + //instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging + if(instance->te > instance->common.te_last) + instance->te = instance->common.te_last; //Option 2 TE averaging + } else { + instance->te = instance->common.te_last; + } + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; instance->common.serial = instance->common.code_found >> 4; instance->common.btn = (uint8_t)instance->common.code_found & 0x00000F; - if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + if(instance->common.callback) + instance->common.callback( + (SubGhzProtocolCommon*)instance, instance->common.context); } instance->common.code_found = 0; instance->common.code_count_bit = 0; break; } - if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot)< instance->common.te_delta) - && (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta*3)) { + if((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < + instance->common.te_delta) && + (DURATION_DIFF(duration, instance->common.te_long) < + instance->common.te_delta * 3)) { subghz_protocol_common_add_bit(&instance->common, 0); instance->common.parser_step = 1; - } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta*3) - && (DURATION_DIFF(duration,instance->common.te_shot)< instance->common.te_delta)) { + } else if( + (DURATION_DIFF(instance->common.te_last, instance->common.te_long) < + instance->common.te_delta * 3) && + (DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 1); instance->common.parser_step = 1; } else { @@ -119,3 +223,92 @@ void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool lev break; } } + +void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + uint64_t code_found_reverse = subghz_protocol_common_reverse_key( + instance->common.code_last_found, instance->common.code_last_count_bit); + + uint32_t code_found_reverse_hi = code_found_reverse >> 32; + uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + + string_cat_printf( + output, + "%s %d Bit te %dus\r\n" + " KEY:0x%lX%08lX\r\n" + " YEK:0x%lX%08lX\r\n" + " SN:0x%05lX BTN:%02X\r\n", + instance->common.name, + instance->common.code_last_count_bit, + instance->te, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + code_found_reverse_lo, + instance->common.serial, + instance->common.btn); +} + +void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output) { + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Te: %d\n" + "Key: %08lX\n", + instance->common.name, + instance->common.code_last_count_bit, + instance->te, + (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); +} + +bool subghz_decoder_princeton_to_load_protocol(FileWorker* file_worker, SubGhzDecoderPrinceton* instance){ + bool loaded = false; + string_t temp_str; + string_init(temp_str); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse te data from 3nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Te: %d\n", &data); + if(res != 1) { + break; + } + instance->te = (uint16_t)data; + + // Read and parse key data from 4nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + uint32_t temp_key = 0; + res = sscanf(string_get_cstr(temp_str), "Key: %08lX\n", &temp_key); + if(res != 1) { + break; + } + instance->common.code_last_found = (uint64_t)temp_key; + instance->common.serial = instance->common.code_last_found >> 4; + instance->common.btn = (uint8_t)instance->common.code_last_found & 0x00000F; + + loaded = true; + } while(0); + + string_clear(temp_str); + + return loaded; +} diff --git a/lib/subghz/protocols/subghz_protocol_princeton.h b/lib/subghz/protocols/subghz_protocol_princeton.h index 8d260462..7feeb978 100644 --- a/lib/subghz/protocols/subghz_protocol_princeton.h +++ b/lib/subghz/protocols/subghz_protocol_princeton.h @@ -2,38 +2,90 @@ #include "subghz_protocol_common.h" -typedef struct SubGhzProtocolPrinceton SubGhzProtocolPrinceton; -/** Allocate SubGhzProtocolPrinceton - * - * @return SubGhzProtocolPrinceton* +/** SubGhzEncoderPrinceton anonymous type */ +typedef struct SubGhzEncoderPrinceton SubGhzEncoderPrinceton; + +/** Allocate SubGhzEncoderPrinceton + * @return pointer to SubGhzEncoderPrinceton instance */ -SubGhzProtocolPrinceton* subghz_protocol_princeton_alloc(); +SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc(); -/** Free SubGhzProtocolPrinceton +/** Free SubGhzEncoderPrinceton instance + * @param instance - SubGhzEncoderPrinceton instance + */ +void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance); + + +/** Reset encoder with new params + * @param instance - SubGhzEncoderPrinceton instance + * @param key - 24bit key + * @param repeat - how many times to repeat + */ +void subghz_encoder_princeton_reset(SubGhzEncoderPrinceton* instance, uint32_t key, size_t repeat); + +/** Get repeat count left + * @param instance - SubGhzEncoderPrinceton instance + * @return repeat count left + */ +size_t subghz_encoder_princeton_get_repeat_left(SubGhzEncoderPrinceton* instance); + +/** Get level duration + * @param instance - SubGhzEncoderPrinceton instance + * @return level duration + */ +LevelDuration subghz_encoder_princeton_yield(void* context); + + +/** SubGhzDecoderPrinceton anonymous type */ +typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton; + + +void subghz_encoder_princeton_set_te( + SubGhzEncoderPrinceton* instance, + void* decoder); + +/** Allocate SubGhzDecoderPrinceton + * + * @return SubGhzDecoderPrinceton* + */ +SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(); + +/** Free SubGhzDecoderPrinceton * * @param instance */ -void subghz_protocol_princeton_free(SubGhzProtocolPrinceton* instance); +void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance); /** Sends the key on the air * - * @param instance - SubGhzProtocolPrinceton instance + * @param instance - SubGhzDecoderPrinceton instance * @param key - key send * @param bit - count bit key * @param repeat - repeat send key */ -void subghz_protocol_princeton_send_key(SubGhzProtocolPrinceton* instance, uint64_t key, uint8_t bit, uint8_t repeat); +void subghz_decoder_princeton_send_key(SubGhzDecoderPrinceton* instance, uint64_t key, uint8_t bit, uint8_t repeat); /** Reset internal state - * @param instance - SubGhzProtocolPrinceton instance + * @param instance - SubGhzDecoderPrinceton instance */ -void subghz_protocol_princeton_reset(SubGhzProtocolPrinceton* instance); +void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance); /** Parse accepted duration * - * @param instance - SubGhzProtocolPrinceton instance + * @param instance - SubGhzDecoderPrinceton instance * @param data - LevelDuration level_duration */ -void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool level, uint32_t duration); +void subghz_decoder_princeton_parse(SubGhzDecoderPrinceton* instance, bool level, uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzDecoderPrinceton* instance + * @param output - output string + */ +void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output); + +void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output); +bool subghz_decoder_princeton_to_load_protocol(FileWorker* file_worker, SubGhzDecoderPrinceton* instance); +