From 9d952ed855af306686625f7c5714319c4d906bec Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Mon, 25 Oct 2021 18:37:14 +0400 Subject: [PATCH] [FL-1913, FL-1963] SubGhz: save raw signal, add came atomo decoder (#783) * File_Worker: getting the name of a new file with an index * SubGhz: add decoder RAW protocol * SubGhz: add view Save RAW * SubGhz: refactoring subghz custom event * SubGhz: fix syntax * SubGhz: fix error build * SubGhz: test build * SubGhz: refactoring subghz, add rename, delete, start and emulate RAW signal * SubGhz: fix triangle glitch in save raw view * SubGhz: fix receiver config scene * SubGhz: fix transfer after returning from save scene * Canvas: add font rotation * SubGhz: raw protocol encoder * SubGhz: fix error completion of transfer raw encoder * SubGhz: increased the speed of reading RAW data from a flash drive, displaying the name of the saved file in the Save RAW scene * Canvas: fix font rotation * SubGhz: fix navigation save RAW scene * SubGhz: add decode came atomo * Git: renormalize * Cleanup sources and enums * Gui: add font direction to canvas reset, canvas init sequence cleanup. * SubGhz: reorder menu. * Gui: correct canvas_set_font_direction signature Co-authored-by: Aleksandr Kutuzov --- .gitattributes | 1 - applications/gui/canvas.c | 23 +- applications/gui/canvas.h | 16 + .../subghz/helpers/subghz_custom_event.h | 28 ++ .../subghz/scenes/subghz_scene_config.h | 3 +- .../subghz/scenes/subghz_scene_delete.c | 10 +- .../scenes/subghz_scene_delete_success.c | 8 +- .../scenes/subghz_scene_frequency_analyzer.c | 10 +- .../subghz/scenes/subghz_scene_receiver.c | 9 +- .../scenes/subghz_scene_receiver_config.c | 39 ++- .../scenes/subghz_scene_receiver_info.c | 22 +- .../subghz/scenes/subghz_scene_save_name.c | 15 +- .../subghz/scenes/subghz_scene_save_raw.c | 169 ++++++++++ .../subghz/scenes/subghz_scene_save_success.c | 7 +- .../subghz/scenes/subghz_scene_show_error.c | 7 +- .../subghz/scenes/subghz_scene_show_only_rx.c | 7 +- .../subghz/scenes/subghz_scene_start.c | 16 +- .../subghz/scenes/subghz_scene_transmitter.c | 26 +- applications/subghz/subghz.c | 12 + applications/subghz/subghz_i.c | 30 +- applications/subghz/subghz_i.h | 5 + .../subghz/views/subghz_frequency_analyzer.h | 7 +- applications/subghz/views/subghz_receiver.c | 7 +- applications/subghz/views/subghz_receiver.h | 9 +- applications/subghz/views/subghz_save_raw.c | 313 ++++++++++++++++++ applications/subghz/views/subghz_save_raw.h | 30 ++ .../subghz/views/subghz_transmitter.c | 6 +- .../subghz/views/subghz_transmitter.h | 10 +- .../targets/f6/furi-hal/furi-hal-subghz.c | 1 + .../targets/f7/furi-hal/furi-hal-subghz.c | 1 + lib/app-scened-template/file-worker.c | 32 +- lib/app-scened-template/file-worker.h | 22 +- lib/subghz/protocols/subghz_protocol_came.c | 3 +- lib/subghz/protocols/subghz_protocol_came.h | 6 +- .../protocols/subghz_protocol_came_atomo.c | 144 ++++++-- .../protocols/subghz_protocol_came_atomo.h | 11 +- .../protocols/subghz_protocol_came_twee.c | 3 +- .../protocols/subghz_protocol_came_twee.h | 4 +- lib/subghz/protocols/subghz_protocol_common.c | 75 +++-- lib/subghz/protocols/subghz_protocol_common.h | 23 +- .../protocols/subghz_protocol_gate_tx.c | 5 +- .../protocols/subghz_protocol_gate_tx.h | 10 +- lib/subghz/protocols/subghz_protocol_keeloq.c | 3 +- lib/subghz/protocols/subghz_protocol_keeloq.h | 10 +- .../protocols/subghz_protocol_nero_radio.c | 3 +- .../protocols/subghz_protocol_nero_radio.h | 15 +- .../protocols/subghz_protocol_nero_sketch.c | 5 +- .../protocols/subghz_protocol_nero_sketch.h | 17 +- .../protocols/subghz_protocol_nice_flo.c | 5 +- .../protocols/subghz_protocol_nice_flo.h | 10 +- .../protocols/subghz_protocol_princeton.c | 3 +- .../protocols/subghz_protocol_princeton.h | 10 +- lib/subghz/protocols/subghz_protocol_raw.c | 265 +++++++++++++++ lib/subghz/protocols/subghz_protocol_raw.h | 64 ++++ lib/subghz/subghz_file_encoder_worker.c | 210 ++++++++++++ lib/subghz/subghz_file_encoder_worker.h | 39 +++ lib/subghz/subghz_parser.c | 16 + lib/subghz/subghz_parser.h | 21 +- lib/toolbox/level_duration.h | 11 + 59 files changed, 1693 insertions(+), 199 deletions(-) mode change 100755 => 100644 applications/gui/canvas.c create mode 100644 applications/subghz/helpers/subghz_custom_event.h create mode 100644 applications/subghz/scenes/subghz_scene_save_raw.c create mode 100644 applications/subghz/views/subghz_save_raw.c create mode 100644 applications/subghz/views/subghz_save_raw.h create mode 100644 lib/subghz/protocols/subghz_protocol_raw.c create mode 100644 lib/subghz/protocols/subghz_protocol_raw.h create mode 100644 lib/subghz/subghz_file_encoder_worker.c create mode 100644 lib/subghz/subghz_file_encoder_worker.h diff --git a/.gitattributes b/.gitattributes index 032c1bd1c..176a458f9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ * text=auto - diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c old mode 100755 new mode 100644 index 1a2bb06fe..bfd2a0afd --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -11,17 +11,20 @@ Canvas* canvas_init() { furi_hal_power_insomnia_enter(); - canvas->orientation = CanvasOrientationHorizontal; + // Setup u8g2 u8g2_Setup_st756x_flipper(&canvas->fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); - - // send init sequence to the display, display is in sleep mode after this + canvas->orientation = CanvasOrientationHorizontal; + // Initialize display u8g2_InitDisplay(&canvas->fb); - // wake up display - u8g2_ClearBuffer(&canvas->fb); + // Wake up display u8g2_SetPowerSave(&canvas->fb, 0); - u8g2_SendBuffer(&canvas->fb); + + // Clear buffer and send to device + canvas_clear(canvas); + canvas_commit(canvas); furi_hal_power_insomnia_exit(); + return canvas; } @@ -32,9 +35,12 @@ void canvas_free(Canvas* canvas) { void canvas_reset(Canvas* canvas) { furi_assert(canvas); + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); + canvas_set_font_direction(canvas, CanvasFontDirectionLeftToRight); } void canvas_commit(Canvas* canvas) { @@ -96,6 +102,11 @@ void canvas_set_color(Canvas* canvas, Color color) { u8g2_SetDrawColor(&canvas->fb, color); } +void canvas_set_font_direction(Canvas* canvas, CanvasFontDirection dir) { + furi_assert(canvas); + u8g2_SetFontDirection(&canvas->fb, dir); +} + void canvas_invert_color(Canvas* canvas) { canvas->fb.draw_color = !canvas->fb.draw_color; } diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index cbf9d0684..59895472c 100644 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -37,6 +37,14 @@ typedef enum { CanvasOrientationVertical, } CanvasOrientation; +/** Font Direction */ +typedef enum { + CanvasFontDirectionLeftToRight, + CanvasFontDirectionTopToDown, + CanvasFontDirectionRightToLeft, + CanvasFontDirectionDownToTop, +} CanvasFontDirection; + /** Canvas anonymouse structure */ typedef struct Canvas Canvas; @@ -77,6 +85,14 @@ void canvas_clear(Canvas* canvas); */ void canvas_set_color(Canvas* canvas, Color color); +/** Set font swap + * Argument String Rotation Description + * + * @param canvas Canvas instance + * @param dir Direction font + */ +void canvas_set_font_direction(Canvas* canvas, CanvasFontDirection dir); + /** Invert drawing color * * @param canvas Canvas instance diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/subghz/helpers/subghz_custom_event.h new file mode 100644 index 000000000..df833b8da --- /dev/null +++ b/applications/subghz/helpers/subghz_custom_event.h @@ -0,0 +1,28 @@ +#pragma once + +typedef enum { + SubghzCustomEventSceneDeleteSuccess = 100, + SubghzCustomEventSceneDelete, + SubghzCustomEventSceneReceiverInfoTxStart, + SubghzCustomEventSceneReceiverInfoTxStop, + SubghzCustomEventSceneReceiverInfoSave, + SubghzCustomEventSceneSaveName, + SubghzCustomEventSceneSaveSuccess, + SubghzCustomEventSceneShowError, + SubghzCustomEventSceneShowOnlyRX, + + SubghzCustomEventViewReceverOK, + SubghzCustomEventViewReceverConfig, + SubghzCustomEventViewReceverBack, + + SubghzCustomEventViewSaveRAWBack, + SubghzCustomEventViewSaveRAWIDLE, + SubghzCustomEventViewSaveRAWREC, + SubghzCustomEventViewSaveRAWConfig, + SubghzCustomEventViewSaveRAWMore, + + SubghzCustomEventViewTransmitterBack, + SubghzCustomEventViewTransmitterSendStart, + SubghzCustomEventViewTransmitterSendStop, + SubghzCustomEventViewTransmitterError, +} SubghzCustomEvent; \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index eca3cc358..0f66e67a6 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -16,4 +16,5 @@ ADD_SCENE(subghz, test_static, TestStatic) ADD_SCENE(subghz, test_carrier, TestCarrier) ADD_SCENE(subghz, test_packet, TestPacket) ADD_SCENE(subghz, set_type, SetType) -ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) \ No newline at end of file +ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) +ADD_SCENE(subghz, save_raw, SaveRAW) \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/subghz/scenes/subghz_scene_delete.c index 94782e885..e79e3a6da 100644 --- a/applications/subghz/scenes/subghz_scene_delete.c +++ b/applications/subghz/scenes/subghz_scene_delete.c @@ -1,15 +1,11 @@ #include "../subghz_i.h" - -typedef enum { - SubGhzSceneDeleteInfoCustomEventDelete, -} SubGhzSceneDeleteInfoCustomEvent; +#include "../helpers/subghz_custom_event.h" void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); SubGhz* subghz = context; if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzSceneDeleteInfoCustomEventDelete); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneDelete); } } @@ -53,7 +49,7 @@ void subghz_scene_delete_on_enter(void* context) { bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzSceneDeleteInfoCustomEventDelete) { + if(event.event == SubghzCustomEventSceneDelete) { memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name)); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); diff --git a/applications/subghz/scenes/subghz_scene_delete_success.c b/applications/subghz/scenes/subghz_scene_delete_success.c index bfafb7e57..04b485319 100644 --- a/applications/subghz/scenes/subghz_scene_delete_success.c +++ b/applications/subghz/scenes/subghz_scene_delete_success.c @@ -1,10 +1,10 @@ #include "../subghz_i.h" - -#define SCENE_DELETE_SUCCESS_CUSTOM_EVENT (0UL) +#include "../helpers/subghz_custom_event.h" void subghz_scene_delete_success_popup_callback(void* context) { SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_DELETE_SUCCESS_CUSTOM_EVENT); + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventSceneDeleteSuccess); } void subghz_scene_delete_success_on_enter(void* context) { @@ -25,7 +25,7 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SCENE_DELETE_SUCCESS_CUSTOM_EVENT) { + if(event.event == SubghzCustomEventSceneDeleteSuccess) { return scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } diff --git a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c index b67494f0e..548a0f8fc 100644 --- a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c +++ b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -1,7 +1,7 @@ #include "../subghz_i.h" #include "../views/subghz_frequency_analyzer.h" -void subghz_scene_frequency_analyzer_callback(SubghzFrequencyAnalyzerEvent event, void* context) { +void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, event); @@ -15,13 +15,7 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) { } bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubghzFrequencyAnalyzerEventOnlyRx) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); - return true; - } - } + //SubGhz* subghz = context; return false; } diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index fe29c0cfc..653cdb1a2 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -34,7 +34,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { string_clear(history_stat_str); } -void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) { +void subghz_scene_receiver_callback(SubghzCustomEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, event); @@ -102,8 +102,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case SubghzReceverEventBack: + case SubghzCustomEventViewReceverBack: // Stop CC1101 Rx + subghz->state_notifications = NOTIFICATION_IDLE_STATE; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); @@ -118,12 +119,12 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart); return true; break; - case SubghzReceverEventOK: + case SubghzCustomEventViewReceverOK: subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); return true; break; - case SubghzReceverEventConfig: + case SubghzCustomEventViewReceverConfig: subghz->state_notifications = NOTIFICATION_IDLE_STATE; subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c index 3991a9993..2a51bee60 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -66,6 +66,8 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { variable_item_set_current_value_text(item, subghz_frequencies_text[index]); subghz->txrx->frequency = subghz_frequencies[index]; + } else { + variable_item_set_current_value_index(item, subghz_frequencies_433_92); } } @@ -88,22 +90,24 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) subghz->scene_manager, SubGhzSceneReceiverConfig), subghz_frequencies_text[subghz_frequencies_433_92]); subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + variable_item_set_current_value_index( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + subghz_frequencies_433_92); } else { variable_item_set_current_value_text( (VariableItem*)scene_manager_get_scene_state( subghz->scene_manager, SubGhzSceneReceiverConfig), " -----"); + variable_item_set_current_value_index( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + subghz_frequencies_433_92); } subghz->txrx->hopper_state = hopping_value[index]; } -void subghz_scene_receiver_config_callback(SubghzReceverEvent event, void* context) { - furi_assert(context); - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, event); -} - void subghz_scene_receiver_config_on_enter(void* context) { SubGhz* subghz = context; VariableItem* item; @@ -122,16 +126,18 @@ void subghz_scene_receiver_config_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]); - item = variable_item_list_add( - subghz->variable_item_list, - "Hopping:", - HOPPING_COUNT, - subghz_scene_receiver_config_set_hopping_runing, - subghz); - value_index = subghz_scene_receiver_config_hopper_value_index( - subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, hopping_text[value_index]); + if(!scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSaveRAW)) { + item = variable_item_list_add( + subghz->variable_item_list, + "Hopping:", + HOPPING_COUNT, + subghz_scene_receiver_config_set_hopping_runing, + subghz); + value_index = subghz_scene_receiver_config_hopper_value_index( + subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, hopping_text[value_index]); + } item = variable_item_list_add( subghz->variable_item_list, @@ -155,4 +161,5 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even void subghz_scene_receiver_config_on_exit(void* context) { SubGhz* subghz = context; variable_item_list_clean(subghz->variable_item_list); + scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneSaveRAW, 0); } diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c index 6b33a6869..110833006 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/subghz/scenes/subghz_scene_receiver_info.c @@ -1,10 +1,5 @@ #include "../subghz_i.h" - -typedef enum { - SubGhzSceneReceiverInfoCustomEventTxStart, - SubGhzSceneReceiverInfoCustomEventTxStop, - SubGhzSceneReceiverInfoCustomEventSave, -} SubGhzSceneReceiverInfoCustomEvent; +#include "../helpers/subghz_custom_event.h" void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -12,13 +7,13 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v if((result == GuiButtonTypeCenter) && (type == InputTypePress)) { view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventTxStart); + subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStart); } else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) { view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventTxStop); + subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStop); } else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventSave); + subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoSave); } } @@ -101,7 +96,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzSceneReceiverInfoCustomEventTxStart) { + if(event.event == SubghzCustomEventSceneReceiverInfoTxStart) { //CC1101 Stop RX -> Start TX if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { subghz->txrx->hopper_state = SubGhzHopperStatePause; @@ -112,7 +107,8 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) if(!subghz_scene_receiver_info_update_parser(subghz)) { return false; } - if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { + if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle || + subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { if(!subghz_tx_start(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } else { @@ -120,7 +116,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) } } return true; - } else if(event.event == SubGhzSceneReceiverInfoCustomEventTxStop) { + } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) { //CC1101 Stop Tx -> Start RX subghz->state_notifications = NOTIFICATION_IDLE_STATE; if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { @@ -135,7 +131,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) } subghz->state_notifications = NOTIFICATION_RX_STATE; return true; - } else if(event.event == SubGhzSceneReceiverInfoCustomEventSave) { + } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) { //CC1101 Stop RX -> Save subghz->state_notifications = NOTIFICATION_IDLE_STATE; if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index ee21238a0..f0ecd0774 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -1,12 +1,11 @@ #include "../subghz_i.h" #include #include "file-worker.h" - -#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL) +#include "../helpers/subghz_custom_event.h" 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); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName); } void subghz_scene_save_name_on_enter(void* context) { @@ -38,12 +37,14 @@ 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(strcmp(subghz->file_name, "") && - subghz_save_protocol_to_file(subghz, subghz->file_name)) { + if(event.event == SubghzCustomEventSceneSaveName) { + if(strcmp(subghz->file_name, "")) { if(strcmp(subghz->file_name_tmp, "")) { - subghz_delete_file(subghz); + subghz_rename_file(subghz); + } else { + subghz_save_protocol_to_file(subghz, subghz->file_name); } + subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); return true; diff --git a/applications/subghz/scenes/subghz_scene_save_raw.c b/applications/subghz/scenes/subghz_scene_save_raw.c new file mode 100644 index 000000000..5399c74e7 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_save_raw.c @@ -0,0 +1,169 @@ +#include "../subghz_i.h" +#include "../views/subghz_save_raw.h" +#include +#include + +static void subghz_scene_save_raw_update_statusbar(void* context) { + furi_assert(context); + SubGhz* subghz = context; + char frequency_str[20]; + char preset_str[10]; + + snprintf( + frequency_str, + sizeof(frequency_str), + "%03ld.%02ld", + subghz->txrx->frequency / 1000000 % 1000, + subghz->txrx->frequency / 10000 % 100); + if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || + subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { + snprintf(preset_str, sizeof(preset_str), "AM"); + } else if( + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { + snprintf(preset_str, sizeof(preset_str), "FM"); + } else { + furi_crash(NULL); + } + subghz_save_raw_add_data_statusbar(subghz->subghz_save_raw, frequency_str, preset_str); +} + +void subghz_scene_save_raw_callback(SubghzCustomEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +void subghz_scene_save_raw_on_enter(void* context) { + SubGhz* subghz = context; + subghz_scene_save_raw_update_statusbar(subghz); + subghz_save_raw_set_callback(subghz->subghz_save_raw, subghz_scene_save_raw_callback, subghz); + + subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, "RAW"); + furi_assert(subghz->txrx->protocol_result); + + subghz_worker_set_pair_callback( + subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_raw_parse); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewSaveRAW); +} + +bool subghz_scene_save_raw_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case SubghzCustomEventViewSaveRAWBack: + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + subghz_sleep(subghz); + }; + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; + subghz_protocol_save_raw_to_file_stop( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result); + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + return true; + break; + case SubghzCustomEventViewSaveRAWConfig: + scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneSaveRAW, 1); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); + return true; + break; + case SubghzCustomEventViewSaveRAWIDLE: + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + subghz_sleep(subghz); + }; + subghz_protocol_save_raw_to_file_stop( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result); + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + //send the name of the saved file to the account + subghz_save_raw_set_file_name( + subghz->subghz_save_raw, + subghz_protocol_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); + return true; + break; + case SubghzCustomEventViewSaveRAWREC: + if(subghz_protocol_save_raw_to_file_init( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, + "Raw", + subghz->txrx->frequency, + subghz->txrx->preset)) { + if((subghz->txrx->txrx_state == SubGhzTxRxStateIdle) || + (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { + subghz_begin(subghz, subghz->txrx->preset); + subghz_rx(subghz, subghz->txrx->frequency); + } + subghz->state_notifications = NOTIFICATION_RX_STATE; + } else { + string_set(subghz->error_str, "No SD card"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + return true; + break; + case SubghzCustomEventViewSaveRAWMore: + if(strcmp( + subghz_protocol_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result), + "")) { + strlcpy( + subghz->file_name, + subghz_protocol_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result), + strlen(subghz_protocol_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)) + + 1); + //set the path to read the file + string_t temp_str; + string_init_printf( + temp_str, + "%s/%s%s", + SUBGHZ_APP_PATH_FOLDER, + subghz->file_name, + SUBGHZ_APP_EXTENSION); + subghz_protocol_set_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); + string_clear(temp_str); + + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); + } + return true; + break; + + default: + break; + } + } else if(event.type == SceneManagerEventTypeTick) { + switch(subghz->state_notifications) { + case NOTIFICATION_RX_STATE: + notification_message(subghz->notifications, &sequence_blink_blue_10); + subghz_save_raw_update_sample_write( + subghz->subghz_save_raw, + subghz_save_protocol_raw_get_sample_write( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); + subghz_save_raw_add_data_rssi(subghz->subghz_save_raw, furi_hal_subghz_get_rssi()); + break; + default: + break; + } + } + return false; +} + +void subghz_scene_save_raw_on_exit(void* context) { + SubGhz* subghz = context; + + //Stop CC1101 + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + subghz_sleep(subghz); + }; + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + + //Сallback restoration + subghz_worker_set_pair_callback( + subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse); +} diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index dc2674868..31e7d3ee9 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -1,10 +1,9 @@ #include "../subghz_i.h" - -#define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) +#include "../helpers/subghz_custom_event.h" 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); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveSuccess); } void subghz_scene_save_success_on_enter(void* context) { @@ -24,7 +23,7 @@ void subghz_scene_save_success_on_enter(void* context) { 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) { + if(event.event == SubghzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/subghz/scenes/subghz_scene_show_error.c b/applications/subghz/scenes/subghz_scene_show_error.c index 2599f24e2..c02ad34aa 100644 --- a/applications/subghz/scenes/subghz_scene_show_error.c +++ b/applications/subghz/scenes/subghz_scene_show_error.c @@ -1,10 +1,9 @@ #include "../subghz_i.h" - -#define SCENE_NO_MAN_CUSTOM_EVENT (11UL) +#include "../helpers/subghz_custom_event.h" void subghz_scene_show_error_popup_callback(void* context) { SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowError); } void subghz_scene_show_error_on_enter(void* context) { @@ -24,7 +23,7 @@ void subghz_scene_show_error_on_enter(void* context) { bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { + if(event.event == SubghzCustomEventSceneShowError) { scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); return true; diff --git a/applications/subghz/scenes/subghz_scene_show_only_rx.c b/applications/subghz/scenes/subghz_scene_show_only_rx.c index e59e1d68d..a62969d4b 100644 --- a/applications/subghz/scenes/subghz_scene_show_only_rx.c +++ b/applications/subghz/scenes/subghz_scene_show_only_rx.c @@ -1,10 +1,9 @@ #include "../subghz_i.h" - -#define SCENE_NO_MAN_CUSTOM_EVENT (11UL) +#include "../helpers/subghz_custom_event.h" void subghz_scene_show_only_rx_popup_callback(void* context) { SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowOnlyRX); } void subghz_scene_show_only_rx_on_enter(void* context) { @@ -30,7 +29,7 @@ void subghz_scene_show_only_rx_on_enter(void* context) { const bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { + if(event.event == SubghzCustomEventSceneShowOnlyRX) { scene_manager_previous_scene(subghz->scene_manager); return true; } diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c index c131a0a81..e36a514b9 100644 --- a/applications/subghz/scenes/subghz_scene_start.c +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -1,11 +1,12 @@ #include "../subghz_i.h" enum SubmenuIndex { - SubmenuIndexRead, + SubmenuIndexRead = 10, SubmenuIndexSaved, SubmenuIndexTest, SubmenuIndexAddManualy, SubmenuIndexFrequencyAnalyzer, + SubmenuIndexSaveRAW, }; void subghz_scene_start_submenu_callback(void* context, uint32_t index) { @@ -20,6 +21,12 @@ void subghz_scene_start_on_enter(void* context) { } submenu_add_item( subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Read Raw", + SubmenuIndexSaveRAW, + subghz_scene_start_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "Saved", SubmenuIndexSaved, subghz_scene_start_submenu_callback, subghz); submenu_add_item( @@ -47,7 +54,12 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexRead) { + if(event.event == SubmenuIndexSaveRAW) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexSaveRAW); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveRAW); + return true; + } else if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index 4aa5f87f0..7dee5bdfd 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -2,13 +2,13 @@ #include "../views/subghz_transmitter.h" #include -void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) { +void subghz_scene_transmitter_callback(SubghzCustomEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, event); } -static void subghz_scene_transmitter_update_data_show(void* context) { +bool subghz_scene_transmitter_update_data_show(void* context) { SubGhz* subghz = context; if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { @@ -51,17 +51,22 @@ static void subghz_scene_transmitter_update_data_show(void* context) { preset_str, show_button); string_clear(key_str); - } else { - string_set(subghz->error_str, "Protocol not found"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + + return true; } + return false; } void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; + if(!subghz_scene_transmitter_update_data_show(subghz)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventViewTransmitterError); + } + subghz_transmitter_set_callback( subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); - subghz_scene_transmitter_update_data_show(subghz); + subghz->state_notifications = NOTIFICATION_IDLE_STATE; view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); } @@ -69,7 +74,7 @@ void subghz_scene_transmitter_on_enter(void* context) { bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubghzTransmitterEventSendStart) { + if(event.event == SubghzCustomEventViewTransmitterSendStart) { subghz->state_notifications = NOTIFICATION_IDLE_STATE; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); @@ -84,18 +89,21 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } } return true; - } else if(event.event == SubghzTransmitterEventSendStop) { + } else if(event.event == SubghzCustomEventViewTransmitterSendStop) { subghz->state_notifications = NOTIFICATION_IDLE_STATE; if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { subghz_tx_stop(subghz); subghz_sleep(subghz); } return true; - } else if(event.event == SubghzTransmitterEventBack) { + } else if(event.event == SubghzCustomEventViewTransmitterBack) { subghz->state_notifications = NOTIFICATION_IDLE_STATE; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); return true; + } else if(event.event == SubghzCustomEventViewTransmitterError) { + string_set(subghz->error_str, "Protocol not found"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == NOTIFICATION_TX_STATE) { diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 7c71e25f4..ff5215812 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -140,6 +140,13 @@ SubGhz* subghz_alloc() { SubGhzViewFrequencyAnalyzer, subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer)); + // Save RAW + subghz->subghz_save_raw = subghz_save_raw_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, + SubGhzViewSaveRAW, + subghz_save_raw_get_view(subghz->subghz_save_raw)); + // Carrier Test Module subghz->subghz_test_carrier = subghz_test_carrier_alloc(); view_dispatcher_add_view( @@ -181,6 +188,7 @@ SubGhz* subghz_alloc() { subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes"); subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_floor_s_rx"); + subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/came_atomo"); //subghz_parser_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); @@ -226,6 +234,10 @@ void subghz_free(SubGhz* subghz) { view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer); + // Save RAW + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewSaveRAW); + subghz_save_raw_free(subghz->subghz_save_raw); + // Submenu view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); submenu_free(subghz->submenu); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 2f849e410..2e3fe6ff0 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -191,7 +191,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { break; } if(!subghz->txrx->protocol_result->to_load_protocol_from_file( - file_worker, subghz->txrx->protocol_result)) { + file_worker, subghz->txrx->protocol_result, string_get_cstr(path))) { break; } loaded = true; @@ -334,8 +334,10 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { if(subghz->txrx->protocol_result == NULL) { break; } - if(!subghz->txrx->protocol_result->to_load_protocol_from_file( - file_worker, subghz->txrx->protocol_result)) { + + if(subghz->txrx->protocol_result->to_load_protocol_from_file == NULL || + !subghz->txrx->protocol_result->to_load_protocol_from_file( + file_worker, subghz->txrx->protocol_result, string_get_cstr(protocol_file_name))) { break; } res = true; @@ -354,6 +356,28 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { return res; } +bool subghz_rename_file(SubGhz* subghz) { + furi_assert(subghz); + bool ret = false; + string_t old_path; + string_t new_path; + + FileWorker* file_worker = file_worker_alloc(false); + + string_init_printf( + old_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); + + string_init_printf( + new_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); + + ret = file_worker_rename(file_worker, string_get_cstr(old_path), string_get_cstr(new_path)); + string_clear(old_path); + string_clear(new_path); + file_worker_close(file_worker); + file_worker_free(file_worker); + return ret; +} + bool subghz_delete_file(SubGhz* subghz) { furi_assert(subghz); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 88be9203d..9e7c1f27d 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -4,6 +4,7 @@ #include "views/subghz_receiver.h" #include "views/subghz_transmitter.h" #include "views/subghz_frequency_analyzer.h" +#include "views/subghz_save_raw.h" #include "views/subghz_test_static.h" #include "views/subghz_test_carrier.h" @@ -64,6 +65,7 @@ struct SubGhzTxRx { SubGhzWorker* worker; SubGhzParser* parser; SubGhzProtocolCommon* protocol_result; + //SubGhzProtocolCommon* protocol_save_raw; SubGhzProtocolCommonEncoder* encoder; uint32_t frequency; FuriHalSubGhzPreset preset; @@ -100,6 +102,7 @@ struct SubGhz { VariableItemList* variable_item_list; SubghzFrequencyAnalyzer* subghz_frequency_analyzer; + SubghzSaveRAW* subghz_save_raw; SubghzTestStatic* subghz_test_static; SubghzTestCarrier* subghz_test_carrier; SubghzTestPacket* subghz_test_packet; @@ -116,6 +119,7 @@ typedef enum { SubGhzViewTransmitter, SubGhzViewVariableItemList, SubGhzViewFrequencyAnalyzer, + SubGhzViewSaveRAW, SubGhzViewStatic, SubGhzViewTestCarrier, SubGhzViewTestPacket, @@ -130,6 +134,7 @@ void subghz_tx_stop(SubGhz* subghz); bool subghz_key_load(SubGhz* subghz, const char* file_path); bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name); bool subghz_load_protocol_from_file(SubGhz* subghz); +bool subghz_rename_file(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); void subghz_file_name_clear(SubGhz* subghz); uint32_t subghz_random_serial(void); diff --git a/applications/subghz/views/subghz_frequency_analyzer.h b/applications/subghz/views/subghz_frequency_analyzer.h index ebfcb1739..78280503a 100644 --- a/applications/subghz/views/subghz_frequency_analyzer.h +++ b/applications/subghz/views/subghz_frequency_analyzer.h @@ -1,14 +1,11 @@ #pragma once #include - -typedef enum { - SubghzFrequencyAnalyzerEventOnlyRx, -} SubghzFrequencyAnalyzerEvent; +#include "../helpers/subghz_custom_event.h" typedef struct SubghzFrequencyAnalyzer SubghzFrequencyAnalyzer; -typedef void (*SubghzFrequencyAnalyzerCallback)(SubghzFrequencyAnalyzerEvent event, void* context); +typedef void (*SubghzFrequencyAnalyzerCallback)(SubghzCustomEvent event, void* context); void subghz_frequency_analyzer_set_callback( SubghzFrequencyAnalyzer* subghz_frequency_analyzer, diff --git a/applications/subghz/views/subghz_receiver.c b/applications/subghz/views/subghz_receiver.c index 26aec5e71..f854e81d0 100644 --- a/applications/subghz/views/subghz_receiver.c +++ b/applications/subghz/views/subghz_receiver.c @@ -181,7 +181,7 @@ bool subghz_receiver_input(InputEvent* event, void* context) { SubghzReceiver* subghz_receiver = context; if(event->key == InputKeyBack && event->type == InputTypeShort) { - subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); + subghz_receiver->callback(SubghzCustomEventViewReceverBack, subghz_receiver->context); } else if( event->key == InputKeyUp && (event->type == InputTypeShort || event->type == InputTypeRepeat)) { @@ -199,12 +199,13 @@ bool subghz_receiver_input(InputEvent* event, void* context) { return true; }); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { - subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); + subghz_receiver->callback(SubghzCustomEventViewReceverConfig, subghz_receiver->context); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { if(model->history_item != 0) { - subghz_receiver->callback(SubghzReceverEventOK, subghz_receiver->context); + subghz_receiver->callback( + SubghzCustomEventViewReceverOK, subghz_receiver->context); } return false; }); diff --git a/applications/subghz/views/subghz_receiver.h b/applications/subghz/views/subghz_receiver.h index be9a9ef1a..e26ee2c2d 100644 --- a/applications/subghz/views/subghz_receiver.h +++ b/applications/subghz/views/subghz_receiver.h @@ -1,16 +1,11 @@ #pragma once #include - -typedef enum { - SubghzReceverEventOK, - SubghzReceverEventConfig, - SubghzReceverEventBack, -} SubghzReceverEvent; +#include "../helpers/subghz_custom_event.h" typedef struct SubghzReceiver SubghzReceiver; -typedef void (*SubghzReceiverCallback)(SubghzReceverEvent event, void* context); +typedef void (*SubghzReceiverCallback)(SubghzCustomEvent event, void* context); void subghz_receiver_set_callback( SubghzReceiver* subghz_receiver, diff --git a/applications/subghz/views/subghz_save_raw.c b/applications/subghz/views/subghz_save_raw.c new file mode 100644 index 000000000..b496cef73 --- /dev/null +++ b/applications/subghz/views/subghz_save_raw.c @@ -0,0 +1,313 @@ +#include "subghz_save_raw.h" +#include "../subghz_i.h" + +#include +#include +#include +#include +#include +#include + +#include +#define SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE 100 + +typedef enum { + SubghzSaveRAWStatusStart, + SubghzSaveRAWStatusIDLE, + SubghzSaveRAWStatusREC, + SubghzSaveRAWStatusShowName, +} SubghzSaveRAWStatus; + +struct SubghzSaveRAW { + View* view; + osTimerId timer; + SubghzSaveRAWCallback callback; + void* context; +}; + +typedef struct { + string_t frequency_str; + string_t preset_str; + string_t sample_write; + string_t file_name; + uint8_t* rssi_history; + bool rssi_history_end; + uint8_t ind_write; + SubghzSaveRAWStatus satus; +} SubghzSaveRAWModel; + +void subghz_save_raw_set_callback( + SubghzSaveRAW* subghz_save_raw, + SubghzSaveRAWCallback callback, + void* context) { + furi_assert(subghz_save_raw); + furi_assert(callback); + subghz_save_raw->callback = callback; + subghz_save_raw->context = context; +} + +void subghz_save_raw_add_data_statusbar( + SubghzSaveRAW* instance, + const char* frequency_str, + const char* preset_str) { + furi_assert(instance); + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + string_set(model->frequency_str, frequency_str); + string_set(model->preset_str, preset_str); + return true; + }); +} + +void subghz_save_raw_set_file_name(SubghzSaveRAW* instance, const char* file_name) { + furi_assert(instance); + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + string_set(model->file_name, file_name); + return true; + }); +} + +static void subghz_save_raw_timer_callback(void* context) { + furi_assert(context); + SubghzSaveRAW* instance = context; + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + model->satus = SubghzSaveRAWStatusIDLE; + return true; + }); +} + +void subghz_save_raw_add_data_rssi(SubghzSaveRAW* instance, float rssi) { + furi_assert(instance); + uint8_t u_rssi = 0; + + if(rssi < -90) { + u_rssi = 0; + } else { + u_rssi = (uint8_t)((rssi + 90) / 2.7); + } + //if(u_rssi > 34) u_rssi = 34; + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + model->rssi_history[model->ind_write++] = u_rssi; + if(model->ind_write > SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE) { + model->rssi_history_end = true; + model->ind_write = 0; + } + return true; + }); +} + +void subghz_save_raw_update_sample_write(SubghzSaveRAW* instance, size_t sample) { + furi_assert(instance); + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + string_printf(model->sample_write, "%d spl.", sample); + return false; + }); +} + +void subghz_save_raw_draw_rssi(Canvas* canvas, SubghzSaveRAWModel* model) { + int ind = 0; + int base = 0; + if(model->rssi_history_end == false) { + for(int i = model->ind_write; i >= 0; i--) { + canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]); + } + if(model->ind_write > 3) { + canvas_draw_line(canvas, model->ind_write, 47, model->ind_write, 13); + canvas_draw_line(canvas, model->ind_write - 2, 12, model->ind_write + 2, 12); + canvas_draw_line(canvas, model->ind_write - 1, 13, model->ind_write + 1, 13); + } + } else { + base = SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE - model->ind_write; + for(int i = SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE; i >= 0; i--) { + ind = i - base; + if(ind < 0) ind += SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE; + canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[ind]); + } + canvas_draw_line( + canvas, SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE, 47, SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE, 13); + canvas_draw_line( + canvas, + SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE - 2, + 12, + SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE + 2, + 12); + canvas_draw_line( + canvas, + SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE - 1, + 13, + SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE + 1, + 13); + } +} + +void subghz_save_raw_draw(Canvas* canvas, SubghzSaveRAWModel* model) { + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + if(model->satus != SubghzSaveRAWStatusShowName) { + canvas_draw_str(canvas, 5, 8, string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 40, 8, string_get_cstr(model->preset_str)); + canvas_draw_str_aligned( + canvas, 126, 0, AlignRight, AlignTop, string_get_cstr(model->sample_write)); + } else { + canvas_draw_str_aligned( + canvas, 61, 1, AlignRight, AlignTop, string_get_cstr(model->file_name)); + canvas_draw_str(canvas, 65, 8, "Saved!"); + } + + canvas_draw_line(canvas, 0, 14, 115, 14); + subghz_save_raw_draw_rssi(canvas, model); + canvas_draw_line(canvas, 0, 48, 115, 48); + canvas_draw_line(canvas, 115, 14, 115, 48); + + if(model->satus == SubghzSaveRAWStatusIDLE) { + elements_button_left(canvas, "Config"); + elements_button_center(canvas, "REC"); + elements_button_right(canvas, "More"); + } else if(model->satus == SubghzSaveRAWStatusStart) { + elements_button_left(canvas, "Config"); + elements_button_center(canvas, "REC"); + } else { + elements_button_center(canvas, "Stop"); + } + + canvas_set_font_direction(canvas, 3); + canvas_draw_str(canvas, 126, 40, "RSSI"); + canvas_set_font_direction(canvas, 0); +} + +bool subghz_save_raw_input(InputEvent* event, void* context) { + furi_assert(context); + SubghzSaveRAW* instance = context; + + if(event->key == InputKeyBack && event->type == InputTypeShort) { + instance->callback(SubghzCustomEventViewSaveRAWBack, instance->context); + } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + if(model->satus == SubghzSaveRAWStatusIDLE || + model->satus == SubghzSaveRAWStatusStart) { + instance->callback(SubghzCustomEventViewSaveRAWConfig, instance->context); + } + return true; + }); + } else if(event->key == InputKeyRight && event->type == InputTypeShort) { + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + if(model->satus == SubghzSaveRAWStatusIDLE) { + instance->callback(SubghzCustomEventViewSaveRAWMore, instance->context); + } + return true; + }); + } else if(event->key == InputKeyOk && event->type == InputTypeShort) { + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + if(model->satus == SubghzSaveRAWStatusIDLE || + model->satus == SubghzSaveRAWStatusStart) { + instance->callback(SubghzCustomEventViewSaveRAWREC, instance->context); + model->satus = SubghzSaveRAWStatusREC; + model->ind_write = 0; + model->rssi_history_end = false; + } else { + instance->callback(SubghzCustomEventViewSaveRAWIDLE, instance->context); + model->satus = SubghzSaveRAWStatusShowName; + osTimerStart(instance->timer, 1024); + } + return true; + }); + } + + if(event->key == InputKeyBack) { + return false; + } + + return true; +} + +void subghz_save_raw_enter(void* context) { + furi_assert(context); + SubghzSaveRAW* instance = context; + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + model->satus = SubghzSaveRAWStatusStart; + model->rssi_history = furi_alloc(SUBGHZ_SAVE_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t)); + model->rssi_history_end = false; + model->ind_write = 0; + string_set(model->sample_write, "0 spl."); + return true; + }); +} + +void subghz_save_raw_exit(void* context) { + furi_assert(context); + SubghzSaveRAW* instance = context; + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + if(model->satus != SubghzSaveRAWStatusIDLE && + model->satus != SubghzSaveRAWStatusStart) { + instance->callback(SubghzCustomEventViewSaveRAWIDLE, instance->context); + model->satus = SubghzSaveRAWStatusStart; + } + string_clean(model->frequency_str); + string_clean(model->preset_str); + string_clean(model->sample_write); + string_clean(model->file_name); + free(model->rssi_history); + return true; + }); +} + +SubghzSaveRAW* subghz_save_raw_alloc() { + SubghzSaveRAW* instance = furi_alloc(sizeof(SubghzSaveRAW)); + + // View allocation and configuration + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzSaveRAWModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_save_raw_draw); + view_set_input_callback(instance->view, subghz_save_raw_input); + view_set_enter_callback(instance->view, subghz_save_raw_enter); + view_set_exit_callback(instance->view, subghz_save_raw_exit); + + instance->timer = osTimerNew(subghz_save_raw_timer_callback, osTimerOnce, instance, NULL); + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + string_init(model->frequency_str); + string_init(model->preset_str); + string_init(model->sample_write); + string_init(model->file_name); + return true; + }); + + return instance; +} + +void subghz_save_raw_free(SubghzSaveRAW* instance) { + furi_assert(instance); + + with_view_model( + instance->view, (SubghzSaveRAWModel * model) { + string_clear(model->frequency_str); + string_clear(model->preset_str); + string_clear(model->sample_write); + string_clear(model->file_name); + return true; + }); + osTimerDelete(instance->timer); + view_free(instance->view); + free(instance); +} + +View* subghz_save_raw_get_view(SubghzSaveRAW* instance) { + furi_assert(instance); + return instance->view; +} \ No newline at end of file diff --git a/applications/subghz/views/subghz_save_raw.h b/applications/subghz/views/subghz_save_raw.h new file mode 100644 index 000000000..25d86cf92 --- /dev/null +++ b/applications/subghz/views/subghz_save_raw.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "../helpers/subghz_custom_event.h" + +typedef struct SubghzSaveRAW SubghzSaveRAW; + +typedef void (*SubghzSaveRAWCallback)(SubghzCustomEvent event, void* context); + +void subghz_save_raw_set_callback( + SubghzSaveRAW* subghz_save_raw, + SubghzSaveRAWCallback callback, + void* context); + +SubghzSaveRAW* subghz_save_raw_alloc(); + +void subghz_save_raw_free(SubghzSaveRAW* subghz_static); + +void subghz_save_raw_add_data_statusbar( + SubghzSaveRAW* instance, + const char* frequency_str, + const char* preset_str); + +void subghz_save_raw_set_file_name(SubghzSaveRAW* instance, const char* file_name); + +void subghz_save_raw_update_sample_write(SubghzSaveRAW* instance, size_t sample); + +void subghz_save_raw_add_data_rssi(SubghzSaveRAW* instance, float rssi); + +View* subghz_save_raw_get_view(SubghzSaveRAW* subghz_static); diff --git a/applications/subghz/views/subghz_transmitter.c b/applications/subghz/views/subghz_transmitter.c index 6e29f5ddf..b5adf3e95 100644 --- a/applications/subghz/views/subghz_transmitter.c +++ b/applications/subghz/views/subghz_transmitter.c @@ -111,10 +111,12 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { }); if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { - subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); + subghz_transmitter->callback( + SubghzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { - subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context); + subghz_transmitter->callback( + SubghzCustomEventViewTransmitterSendStop, subghz_transmitter->context); return true; } diff --git a/applications/subghz/views/subghz_transmitter.h b/applications/subghz/views/subghz_transmitter.h index 8ddeaaf86..995e08f66 100644 --- a/applications/subghz/views/subghz_transmitter.h +++ b/applications/subghz/views/subghz_transmitter.h @@ -1,17 +1,11 @@ #pragma once #include - -typedef enum { - SubghzTransmitterEventSendStart, - SubghzTransmitterEventSendStop, - SubghzTransmitterEventBack, - SubghzTransmitterEventNoMan, -} SubghzTransmitterEvent; +#include "../helpers/subghz_custom_event.h" typedef struct SubghzTransmitter SubghzTransmitter; -typedef void (*SubghzTransmitterCallback)(SubghzTransmitterEvent event, void* context); +typedef void (*SubghzTransmitterCallback)(SubghzCustomEvent event, void* context); void subghz_transmitter_set_callback( SubghzTransmitter* subghz_transmitter, diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index 02b912773..e25c40d17 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -658,6 +658,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { bool is_odd = samples % 2; LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + if(level_duration_is_wait(ld)) return; if(level_duration_is_reset(ld)) { // One more even sample required to end at low level if(is_odd) { diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c index 02b912773..e25c40d17 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -658,6 +658,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { bool is_odd = samples % 2; LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + if(level_duration_is_wait(ld)) return; if(level_duration_is_reset(ld)) { // One more even sample required to end at low level if(is_odd) { diff --git a/lib/app-scened-template/file-worker.c b/lib/app-scened-template/file-worker.c index c38c1261a..dec23cf21 100644 --- a/lib/app-scened-template/file-worker.c +++ b/lib/app-scened-template/file-worker.c @@ -79,6 +79,32 @@ bool file_worker_remove(FileWorker* file_worker, const char* filename) { return file_worker_check_common_errors(file_worker); } +void file_worker_get_next_filename( + FileWorker* file_worker, + const char* dirname, + const char* filename, + const char* fileextension, + string_t nextfilename) { + string_t temp_str; + string_init(temp_str); + uint16_t num = 0; + + string_printf(temp_str, "%s/%s%s", dirname, filename, fileextension); + + while(storage_common_stat(file_worker->api, string_get_cstr(temp_str), NULL) == FSE_OK) { + num++; + string_printf(temp_str, "%s/%s%d%s", dirname, filename, num, fileextension); + } + + if(num) { + string_printf(nextfilename, "%s%d", filename, num); + } else { + string_printf(nextfilename, "%s", filename); + } + + string_clear(temp_str); +} + bool file_worker_read(FileWorker* file_worker, void* buffer, uint16_t bytes_to_read) { if(!file_worker_read_internal(file_worker, buffer, bytes_to_read)) { return false; @@ -355,7 +381,11 @@ bool file_worker_read_until_buffered( return string_size(str_result) || *file_buf_cnt; } -bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value) { +bool file_worker_get_value_from_key( + FileWorker* file_worker, + string_t key, + char delimiter, + string_t value) { bool found = false; string_t next_line; string_t next_key; diff --git a/lib/app-scened-template/file-worker.h b/lib/app-scened-template/file-worker.h index 3a2b83de9..1b5f34072 100644 --- a/lib/app-scened-template/file-worker.h +++ b/lib/app-scened-template/file-worker.h @@ -68,6 +68,22 @@ bool file_worker_mkdir(FileWorker* file_worker, const char* dirname); */ bool file_worker_remove(FileWorker* file_worker, const char* filename); +/** + * @brief Get next free filename. + * + * @param file_worker FileWorker instance + * @param dirname + * @param filename + * @param fileextension + * @param nextfilename return name + */ +void file_worker_get_next_filename( + FileWorker* file_worker, + const char* dirname, + const char* filename, + const char* fileextension, + string_t nextfilename); + /** * @brief Reads data from a file. * @@ -194,7 +210,11 @@ bool file_worker_read_until_buffered( * @param value value for given key * @return true on success */ -bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value); +bool file_worker_get_value_from_key( + FileWorker* file_worker, + string_t key, + char delimiter, + string_t value); /** * @brief Check whether file exist or not diff --git a/lib/subghz/protocols/subghz_protocol_came.c b/lib/subghz/protocols/subghz_protocol_came.c index cb1c67200..866e577b5 100644 --- a/lib/subghz/protocols/subghz_protocol_came.c +++ b/lib/subghz/protocols/subghz_protocol_came.c @@ -182,7 +182,8 @@ void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t out bool subghz_protocol_came_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolCame* instance) { + SubGhzProtocolCame* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_came.h b/lib/subghz/protocols/subghz_protocol_came.h index 3edcd8f99..603ca21a5 100644 --- a/lib/subghz/protocols/subghz_protocol_came.h +++ b/lib/subghz/protocols/subghz_protocol_came.h @@ -56,15 +56,17 @@ void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t out * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolCame instance + * @param file_path - file path * @return bool */ bool subghz_protocol_came_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolCame* instance); + SubGhzProtocolCame* instance, + const char* file_path); /** Loading protocol from bin data * * @param instance - SubGhzProtocolCame instance * @param context - SubGhzProtocolCommonLoad context */ -void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context); \ No newline at end of file +void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context); diff --git a/lib/subghz/protocols/subghz_protocol_came_atomo.c b/lib/subghz/protocols/subghz_protocol_came_atomo.c index 0422ff6a5..37c0860f8 100644 --- a/lib/subghz/protocols/subghz_protocol_came_atomo.c +++ b/lib/subghz/protocols/subghz_protocol_came_atomo.c @@ -2,9 +2,12 @@ #include "subghz_protocol_common.h" #include +#define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF + struct SubGhzProtocolCameAtomo { SubGhzProtocolCommon common; ManchesterState manchester_saved_state; + const char* rainbow_table_file_name; }; typedef enum { @@ -39,11 +42,118 @@ void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance) { free(instance); } +void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name) { + instance->rainbow_table_file_name = name; + printf("Loading CAME Atomo rainbow table %s\r\n", name); +} + +/** Read bytes from rainbow table + * + * @param instance - SubGhzProtocolCameAtomo* instance + * @param number_atomo_magic_xor + * @return atomo_magic_xor + */ +uint64_t subghz_came_atomo_get_atomo_magic_xor_in_file( + SubGhzProtocolCameAtomo* instance, + uint8_t number_atomo_magic_xor) { + if(!strcmp(instance->rainbow_table_file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE; + + uint8_t buffer[sizeof(uint64_t)] = {0}; + uint32_t address = number_atomo_magic_xor * sizeof(uint64_t); + uint64_t atomo_magic_xor = 0; + + FileWorker* file_worker = file_worker_alloc(true); + if(file_worker_open( + file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) { + file_worker_seek(file_worker, address, true); + file_worker_read(file_worker, &buffer, sizeof(uint64_t)); + for(size_t i = 0; i < sizeof(uint64_t); i++) { + atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i]; + } + } else { + atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE; + } + file_worker_close(file_worker); + file_worker_free(file_worker); + + return atomo_magic_xor; +} + /** Analysis of received data * * @param instance SubGhzProtocolCameAtomo instance */ void subghz_protocol_came_atomo_remote_controller(SubGhzProtocolCameAtomo* instance) { + /* + * 0x1fafef3ed0f7d9ef + * 0x185fcc1531ee86e7 + * 0x184fa96912c567ff + * 0x187f8a42f3dc38f7 + * 0x186f63915492a5cd + * 0x181f40bab58bfac5 + * 0x180f25c696a01bdd + * 0x183f06ed77b944d5 + * 0x182ef661d83d21a9 + * 0x18ded54a39247ea1 + * 0x18ceb0361a0f9fb9 + * 0x18fe931dfb16c0b1 + * 0x18ee7ace5c585d8b + * ........ + * transmission consists of 99 parcels with increasing counter while holding down the button + * with each new press, the counter in the encrypted part increases + * + * 0x1FAFF13ED0F7D9EF + * 0x1FAFF11ED0F7D9EF + * 0x1FAFF10ED0F7D9EF + * 0x1FAFF0FED0F7D9EF + * 0x1FAFF0EED0F7D9EF + * 0x1FAFF0DED0F7D9EF + * 0x1FAFF0CED0F7D9EF + * 0x1FAFF0BED0F7D9EF + * 0x1FAFF0AED0F7D9EF + * + * where 0x1FAF - parcel counter, 0хF0A - button press counter, + * 0xED0F7D9E - serial number, 0хF - key + * 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F = 0x07F0 + * 0x185f ^ 0x185F = 0x0000 + * 0x184f ^ 0x185F = 0x0010 + * 0x187f ^ 0x185F = 0x0020 + * ..... + * 0x182e ^ 0x185F = 0x0071 + * 0x18de ^ 0x185F = 0x0081 + * ..... + * 0x1e43 ^ 0x185F = 0x061C + * where the last nibble is incremented every 8 samples + * + * Decode + * + * 0x1cf6931dfb16c0b1 => 0x1cf6 + * 0x1cf6 ^ 0x185F = 0x04A9 + * 0x04A9 => 0x04A = 74 (dec) + * 74+1 % 32(atomo_magic_xor) = 11 + * GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX + * 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX = 0xEF3ED0F7D9EF + * 0xEF3 ED0F7D9E F => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key + * + * */ + + uint16_t parcel_counter = instance->common.code_last_found >> 48; + parcel_counter = parcel_counter ^ 0x185F; + parcel_counter >>= 4; + uint8_t ind = (parcel_counter + 1) % 32; + uint64_t temp_data = instance->common.code_last_found & 0x0000FFFFFFFFFFFF; + uint64_t atomo_magic_xor = subghz_came_atomo_get_atomo_magic_xor_in_file(instance, ind); + + if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) { + temp_data = temp_data ^ atomo_magic_xor; + instance->common.cnt = temp_data >> 36; + instance->common.serial = (temp_data >> 4) & 0x000FFFFFFFF; + instance->common.btn = temp_data & 0xF; + } else { + instance->common.cnt = 0; + instance->common.serial = 0; + instance->common.btn = 0; + } } void subghz_protocol_came_atomo_reset(SubGhzProtocolCameAtomo* instance) { @@ -89,26 +199,10 @@ void subghz_protocol_came_atomo_parse( } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) { event = ManchesterEventLongLow; } else if(duration >= (instance->common.te_long * 2 + instance->common.te_delta)) { - if(instance->common.code_count_bit >= + if(instance->common.code_count_bit == instance->common.code_min_count_bit_for_found) { instance->common.code_last_found = instance->common.code_found; instance->common.code_last_count_bit = instance->common.code_count_bit; - // 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; - // FURI_LOG_I( - // "ATOMO", - // "%08lX%08lX %08lX%08lX %d", - // code_found_hi, - // code_found_lo, - // code_found_reverse_hi, - // code_found_reverse_lo, - // instance->common.code_last_count_bit); if(instance->common.callback) instance->common.callback( (SubGhzProtocolCommon*)instance, instance->common.context); @@ -151,17 +245,24 @@ void subghz_protocol_came_atomo_parse( } } void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string_t output) { + subghz_protocol_came_atomo_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; string_cat_printf( output, - "%s %dbit\r\n" - "Key:0x%lX%08lX\r\n", + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%08lX Btn:0x%01X\r\n" + "Cnt:0x%03X\r\n", + instance->common.name, instance->common.code_last_count_bit, code_found_hi, - code_found_lo); + code_found_lo, + instance->common.serial, + instance->common.btn, + instance->common.cnt); } // void subghz_protocol_came_atomo_to_save_str(SubGhzProtocolCameAtomo* instance, string_t output) { @@ -178,7 +279,8 @@ void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string // bool subghz_protocol_came_atomo_to_load_protocol_from_file( // FileWorker* file_worker, -// SubGhzProtocolCameAtomo* instance) { +// SubGhzProtocolCameAtomo* instance, +// const char* file_path) { // bool loaded = false; // string_t temp_str; // string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_came_atomo.h b/lib/subghz/protocols/subghz_protocol_came_atomo.h index 9547fec28..2b349399f 100644 --- a/lib/subghz/protocols/subghz_protocol_came_atomo.h +++ b/lib/subghz/protocols/subghz_protocol_came_atomo.h @@ -16,6 +16,13 @@ SubGhzProtocolCameAtomo* subghz_protocol_came_atomo_alloc(); */ void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance); +/** File name rainbow table CAME Atomo + * + * @param instance - SubGhzProtocolCameAtomo instance + * @param file_name - "path/file_name" + */ +void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name); + // /** Get upload protocol // * // * @param instance - SubGhzProtocolCameAtomo instance @@ -59,11 +66,13 @@ void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string // * // * @param file_worker - FileWorker file_worker // * @param instance - SubGhzProtocolCameAtomo instance +// * @param file_path - file path // * @return bool // */ // bool subghz_protocol_came_atomo_to_load_protocol_from_file( // FileWorker* file_worker, -// SubGhzProtocolCameAtomo* instance); +// SubGhzProtocolCameAtomo* instance, +// const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_came_twee.c b/lib/subghz/protocols/subghz_protocol_came_twee.c index 7a7274e85..8e527c8f7 100644 --- a/lib/subghz/protocols/subghz_protocol_came_twee.c +++ b/lib/subghz/protocols/subghz_protocol_came_twee.c @@ -341,7 +341,8 @@ void subghz_protocol_came_twee_to_save_str(SubGhzProtocolCameTwee* instance, str bool subghz_protocol_came_twee_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolCameTwee* instance) { + SubGhzProtocolCameTwee* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_came_twee.h b/lib/subghz/protocols/subghz_protocol_came_twee.h index 09a36e215..c8f3d465f 100644 --- a/lib/subghz/protocols/subghz_protocol_came_twee.h +++ b/lib/subghz/protocols/subghz_protocol_came_twee.h @@ -59,11 +59,13 @@ void subghz_protocol_came_twee_to_save_str(SubGhzProtocolCameTwee* instance, str * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolCameTwee instance + * @param file_path - file path * @return bool */ bool subghz_protocol_came_twee_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolCameTwee* instance); + SubGhzProtocolCameTwee* instance, + const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_common.c b/lib/subghz/protocols/subghz_protocol_common.c index 2bc0133dd..be1fea94e 100644 --- a/lib/subghz/protocols/subghz_protocol_common.c +++ b/lib/subghz/protocols/subghz_protocol_common.c @@ -2,7 +2,6 @@ #include #include - SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc() { SubGhzProtocolCommonEncoder* instance = furi_alloc(sizeof(SubGhzProtocolCommonEncoder)); instance->upload = furi_alloc(SUBGHZ_ENCODER_UPLOAD_MAX_SIZE * sizeof(LevelDuration)); @@ -13,6 +12,9 @@ SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc() { void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance) { furi_assert(instance); + if(instance->callback_end) { + instance->callback_end((SubGhzProtocolCommon*)instance->context_end); + } free(instance->upload); free(instance); } @@ -22,10 +24,34 @@ size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instan return instance->repeat; } +void subghz_protocol_encoder_common_set_callback( + SubGhzProtocolCommonEncoder* instance, + SubGhzProtocolCommonEncoderCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + instance->callback = callback; + instance->context = context; +} + +void subghz_protocol_encoder_common_set_callback_end( + SubGhzProtocolCommonEncoder* instance, + SubGhzProtocolCommonEncoderCallbackEnd callback_end, + void* context_end) { + furi_assert(instance); + furi_assert(callback_end); + instance->callback_end = callback_end; + instance->context_end = context_end; +} + LevelDuration subghz_protocol_encoder_common_yield(void* context) { SubGhzProtocolCommonEncoder* instance = context; - if(instance->repeat == 0){ + if(instance->callback) { + return instance->callback((SubGhzProtocolCommon*)instance->context); + } + + if(instance->repeat == 0) { return level_duration_reset(); } @@ -39,46 +65,53 @@ LevelDuration subghz_protocol_encoder_common_yield(void* context) { return ret; } -void subghz_protocol_common_add_bit(SubGhzProtocolCommon *common, uint8_t bit){ +void subghz_protocol_common_add_bit(SubGhzProtocolCommon* common, uint8_t bit) { common->code_found = common->code_found << 1 | bit; common->code_count_bit++; } -bool subghz_protocol_common_check_interval(SubGhzProtocolCommon *common, uint32_t duration, uint16_t duration_check) { - if ((duration_check >= (duration - common->te_delta))&&(duration_check <= (duration + common->te_delta))){ +bool subghz_protocol_common_check_interval( + SubGhzProtocolCommon* common, + uint32_t duration, + uint16_t duration_check) { + if((duration_check >= (duration - common->te_delta)) && + (duration_check <= (duration + common->te_delta))) { return true; } else { return false; } } -uint64_t subghz_protocol_common_reverse_key(uint64_t key, uint8_t count_bit){ - uint64_t key_reverse=0; - for(uint8_t i=0; icallback = callback; common->context = context; } - void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output) { - if (instance->to_string) { + if(instance->to_string) { instance->to_string(instance, output); } else { uint32_t code_found_hi = instance->code_found >> 32; uint32_t code_found_lo = instance->code_found & 0x00000000ffffffff; - uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->code_found, instance->code_count_bit); + uint64_t code_found_reverse = + subghz_protocol_common_reverse_key(instance->code_found, instance->code_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; - if (code_found_hi>0) { + if(code_found_hi > 0) { string_cat_printf( output, "Protocol %s, %d Bit\r\n" @@ -92,8 +125,7 @@ void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t outp code_found_reverse_hi, code_found_reverse_lo, instance->serial, - instance->btn - ); + instance->btn); } else { string_cat_printf( output, @@ -108,8 +140,7 @@ void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t outp code_found_reverse_hi, code_found_reverse_lo, instance->serial, - instance->btn - ); + instance->btn); } } } @@ -124,9 +155,9 @@ bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len) if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) && hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) { buff[i] = (nibble_high << 4) | nibble_low; - if(string_size(str)>2){ + if(string_size(str) > 2) { string_right(str, 2); - }else if(icommon.code_last_found = data->code_found; instance->common.code_last_count_bit = data->code_count_bit; subghz_protocol_gate_tx_check_remote_controller(instance); -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/subghz_protocol_gate_tx.h b/lib/subghz/protocols/subghz_protocol_gate_tx.h index 7b91f7dcf..57ca5832d 100644 --- a/lib/subghz/protocols/subghz_protocol_gate_tx.h +++ b/lib/subghz/protocols/subghz_protocol_gate_tx.h @@ -22,7 +22,9 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance); * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ -bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolCommonEncoder* encoder); +bool subghz_protocol_gate_tx_send_key( + SubGhzProtocolGateTX* instance, + SubGhzProtocolCommonEncoder* encoder); /** Reset internal state * @param instance - SubGhzProtocolGateTX instance @@ -54,9 +56,13 @@ void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_ * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolGateTX instance + * @param file_path - file path * @return bool */ -bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance); +bool subghz_protocol_gate_tx_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolGateTX* instance, + const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 9c81dc09c..609809caf 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -436,7 +436,8 @@ void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t bool subghz_protocol_keeloq_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolKeeloq* instance) { + SubGhzProtocolKeeloq* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.h b/lib/subghz/protocols/subghz_protocol_keeloq.h index 7b2cc6d8c..4312f653a 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq.h @@ -53,7 +53,9 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context); * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ -bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProtocolCommonEncoder* encoder); +bool subghz_protocol_keeloq_send_key( + SubGhzProtocolKeeloq* instance, + SubGhzProtocolCommonEncoder* encoder); /** Reset internal state * @param instance - SubGhzProtocolKeeloq instance @@ -85,9 +87,13 @@ void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolKeeloq instance + * @param file_path - file path * @return bool */ -bool subghz_protocol_keeloq_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolKeeloq* instance); +bool subghz_protocol_keeloq_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolKeeloq* instance, + const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_nero_radio.c b/lib/subghz/protocols/subghz_protocol_nero_radio.c index 2331e3ab4..af2a8f1b1 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_radio.c +++ b/lib/subghz/protocols/subghz_protocol_nero_radio.c @@ -245,7 +245,8 @@ void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, s bool subghz_protocol_nero_radio_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolNeroRadio* instance) { + SubGhzProtocolNeroRadio* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_nero_radio.h b/lib/subghz/protocols/subghz_protocol_nero_radio.h index 11f13201c..8d00aad2c 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_radio.h +++ b/lib/subghz/protocols/subghz_protocol_nero_radio.h @@ -22,7 +22,9 @@ void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance); * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ -bool subghz_protocol_nero_radio_send_key(SubGhzProtocolNeroRadio* instance, SubGhzProtocolCommonEncoder* encoder); +bool subghz_protocol_nero_radio_send_key( + SubGhzProtocolNeroRadio* instance, + SubGhzProtocolCommonEncoder* encoder); /** Reset internal state * @param instance - SubGhzProtocolNeroRadio instance @@ -40,7 +42,10 @@ void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* * @param instance - SubGhzProtocolNeroRadio instance * @param data - LevelDuration level_duration */ -void subghz_protocol_nero_radio_parse(SubGhzProtocolNeroRadio* instance, bool level, uint32_t duration); +void subghz_protocol_nero_radio_parse( + SubGhzProtocolNeroRadio* instance, + bool level, + uint32_t duration); /** Outputting information from the parser * @@ -60,9 +65,13 @@ void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, s * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolNeroRadio instance + * @param file_path - file path * @return bool */ -bool subghz_protocol_nero_radio_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroRadio* instance); +bool subghz_protocol_nero_radio_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolNeroRadio* instance, + const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_nero_sketch.c b/lib/subghz/protocols/subghz_protocol_nero_sketch.c index 24a7efc07..c1948ecfd 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_sketch.c +++ b/lib/subghz/protocols/subghz_protocol_nero_sketch.c @@ -238,7 +238,8 @@ void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, bool subghz_protocol_nero_sketch_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolNeroSketch* instance) { + SubGhzProtocolNeroSketch* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); @@ -282,4 +283,4 @@ void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* insta SubGhzProtocolCommonLoad* data = context; instance->common.code_last_found = data->code_found; instance->common.code_last_count_bit = data->code_count_bit; -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/subghz_protocol_nero_sketch.h b/lib/subghz/protocols/subghz_protocol_nero_sketch.h index 0fe781c8e..8c3af2251 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_sketch.h +++ b/lib/subghz/protocols/subghz_protocol_nero_sketch.h @@ -22,7 +22,9 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance); * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ -bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolCommonEncoder* encoder); +bool subghz_protocol_nero_sketch_send_key( + SubGhzProtocolNeroSketch* instance, + SubGhzProtocolCommonEncoder* encoder); /** Reset internal state * @param instance - SubGhzProtocolNeroSketch instance @@ -40,7 +42,10 @@ void subghz_protocol_nero_sketch_check_remote_controller(SubGhzProtocolNeroSketc * @param instance - SubGhzProtocolNeroSketch instance * @param data - LevelDuration level_duration */ -void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool level, uint32_t duration); +void subghz_protocol_nero_sketch_parse( + SubGhzProtocolNeroSketch* instance, + bool level, + uint32_t duration); /** Outputting information from the parser * @@ -60,13 +65,17 @@ void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolNeroSketch instance + * @param file_path - file path * @return bool */ -bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance); +bool subghz_protocol_nero_sketch_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolNeroSketch* instance, + const char* file_path); /** Loading protocol from bin data * * @param instance - SubGhzProtocolNeroSketch instance * @param context - SubGhzProtocolCommonLoad context */ -void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context); \ No newline at end of file +void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context); diff --git a/lib/subghz/protocols/subghz_protocol_nice_flo.c b/lib/subghz/protocols/subghz_protocol_nice_flo.c index 25991380f..6c16315ef 100644 --- a/lib/subghz/protocols/subghz_protocol_nice_flo.c +++ b/lib/subghz/protocols/subghz_protocol_nice_flo.c @@ -179,7 +179,8 @@ void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, strin bool subghz_protocol_nice_flo_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzProtocolNiceFlo* instance) { + SubGhzProtocolNiceFlo* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); @@ -224,4 +225,4 @@ void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, v instance->common.code_last_count_bit = data->code_count_bit; instance->common.serial = 0x0; instance->common.btn = 0x0; -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/subghz_protocol_nice_flo.h b/lib/subghz/protocols/subghz_protocol_nice_flo.h index c5ed8759d..3695fea32 100644 --- a/lib/subghz/protocols/subghz_protocol_nice_flo.h +++ b/lib/subghz/protocols/subghz_protocol_nice_flo.h @@ -22,7 +22,9 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance); * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ -bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolCommonEncoder* encoder); +bool subghz_protocol_nice_flo_send_key( + SubGhzProtocolNiceFlo* instance, + SubGhzProtocolCommonEncoder* encoder); /** Reset internal state * @param instance - SubGhzProtocolNiceFlo instance @@ -54,9 +56,13 @@ void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, strin * * @param file_worker - FileWorker file_worker * @param instance - SubGhzProtocolNiceFlo instance + * @param file_path - file path * @return bool */ -bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance); +bool subghz_protocol_nice_flo_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolNiceFlo* instance, + const char* file_path); /** Loading protocol from bin data * diff --git a/lib/subghz/protocols/subghz_protocol_princeton.c b/lib/subghz/protocols/subghz_protocol_princeton.c index 822a59173..81b65592b 100644 --- a/lib/subghz/protocols/subghz_protocol_princeton.c +++ b/lib/subghz/protocols/subghz_protocol_princeton.c @@ -308,7 +308,8 @@ void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, stri bool subghz_decoder_princeton_to_load_protocol_from_file( FileWorker* file_worker, - SubGhzDecoderPrinceton* instance) { + SubGhzDecoderPrinceton* instance, + const char* file_path) { bool loaded = false; string_t temp_str; string_init(temp_str); diff --git a/lib/subghz/protocols/subghz_protocol_princeton.h b/lib/subghz/protocols/subghz_protocol_princeton.h index 9ccb7cd31..b8c448d20 100644 --- a/lib/subghz/protocols/subghz_protocol_princeton.h +++ b/lib/subghz/protocols/subghz_protocol_princeton.h @@ -111,15 +111,17 @@ void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, stri * * @param file_worker - FileWorker file_worker * @param instance - SubGhzDecoderPrinceton instance + * @param file_path - file path * @return bool */ -bool subghz_decoder_princeton_to_load_protocol_from_file(FileWorker* file_worker, SubGhzDecoderPrinceton* instance); +bool subghz_decoder_princeton_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzDecoderPrinceton* instance, + const char* file_path); /** Loading protocol from bin data * * @param instance - SubGhzDecoderPrinceton instance * @param context - SubGhzProtocolCommonLoad context */ -void subghz_decoder_princeton_to_load_protocol( - SubGhzDecoderPrinceton* instance, - void* context) ; +void subghz_decoder_princeton_to_load_protocol(SubGhzDecoderPrinceton* instance, void* context); diff --git a/lib/subghz/protocols/subghz_protocol_raw.c b/lib/subghz/protocols/subghz_protocol_raw.c new file mode 100644 index 000000000..8d2311c65 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_raw.c @@ -0,0 +1,265 @@ +#include "subghz_protocol_raw.h" +#include "file-worker.h" +#include "../subghz_file_encoder_worker.h" + +#define SUBGHZ_DOWNLOAD_MAX_SIZE 512 + +struct SubGhzProtocolRAW { + SubGhzProtocolCommon common; + + int16_t* upload_raw; + uint16_t ind_write; + FileWorker* file_worker; + SubGhzFileEncoderWorker* file_worker_encoder; + uint32_t file_is_open; + string_t file_name; + size_t sample_write; + bool last_level; +}; + +typedef enum { + RAWFileIsOpenClose = 0, + RAWFileIsOpenWrite, + RAWFileIsOpenRead, +} RAWFilIsOpen; + +SubGhzProtocolRAW* subghz_protocol_raw_alloc(void) { + SubGhzProtocolRAW* instance = furi_alloc(sizeof(SubGhzProtocolRAW)); + + instance->upload_raw = NULL; + instance->ind_write = 0; + + instance->last_level = false; + + instance->file_worker = file_worker_alloc(false); + instance->file_is_open = RAWFileIsOpenClose; + string_init(instance->file_name); + + instance->common.name = "RAW"; + instance->common.code_min_count_bit_for_found = 0; + instance->common.te_short = 80; + instance->common.te_long = 32700; + instance->common.te_delta = 0; + instance->common.type_protocol = SubGhzProtocolCommonTypeRAW; + instance->common.to_load_protocol_from_file = + (SubGhzProtocolCommonLoadFromFile)subghz_protocol_raw_to_load_protocol_from_file; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_raw_to_str; + //instance->common.to_load_protocol = + // (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_raw_to_load_protocol; + instance->common.get_upload_protocol = + (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_raw_send_key; + + return instance; +} + +void subghz_protocol_raw_free(SubGhzProtocolRAW* instance) { + furi_assert(instance); + string_clear(instance->file_name); + file_worker_free(instance->file_worker); + free(instance); +} + +void subghz_protocol_raw_file_encoder_worker_stop(void* context) { + furi_assert(context); + SubGhzProtocolRAW* instance = context; + if(subghz_file_encoder_worker_is_running(instance->file_worker_encoder)) { + subghz_file_encoder_worker_stop(instance->file_worker_encoder); + subghz_file_encoder_worker_free(instance->file_worker_encoder); + instance->file_is_open = RAWFileIsOpenClose; + } +} + +bool subghz_protocol_raw_send_key( + SubGhzProtocolRAW* instance, + SubGhzProtocolCommonEncoder* encoder) { + furi_assert(instance); + furi_assert(encoder); + + bool loaded = false; + + instance->file_worker_encoder = subghz_file_encoder_worker_alloc(); + + if(subghz_file_encoder_worker_start( + instance->file_worker_encoder, string_get_cstr(instance->file_name))) { + //the worker needs a file in order to open and read part of the file + osDelay(100); + instance->file_is_open = RAWFileIsOpenRead; + subghz_protocol_encoder_common_set_callback( + encoder, subghz_file_encoder_worker_get_level_duration, instance->file_worker_encoder); + subghz_protocol_encoder_common_set_callback_end( + encoder, subghz_protocol_raw_file_encoder_worker_stop, instance); + + loaded = true; + } else { + subghz_protocol_raw_file_encoder_worker_stop(instance); + } + return loaded; +} + +void subghz_protocol_raw_reset(SubGhzProtocolRAW* instance) { + instance->ind_write = 0; +} + +void subghz_protocol_raw_parse(SubGhzProtocolRAW* instance, bool level, uint32_t duration) { + if(instance->upload_raw != NULL) { + if(duration > instance->common.te_short) { + if(duration > instance->common.te_long) duration = instance->common.te_long; + if(instance->last_level != level) { + instance->last_level = (level ? true : false); + instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); + } + } + + if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { + subghz_protocol_save_raw_to_file_write(instance); + } + } +} + +void subghz_protocol_raw_to_str(SubGhzProtocolRAW* instance, string_t output) { + string_cat_printf(output, "RAW Date"); +} + +const char* subghz_protocol_get_last_file_name(SubGhzProtocolRAW* instance) { + return string_get_cstr(instance->file_name); +} + +void subghz_protocol_set_last_file_name(SubGhzProtocolRAW* instance, const char* name) { + string_printf(instance->file_name, "%s", name); +} + +bool subghz_protocol_save_raw_to_file_init( + SubGhzProtocolRAW* instance, + const char* dev_name, + uint32_t frequency, + FuriHalSubGhzPreset preset) { + furi_assert(instance); + + string_t dev_file_name; + string_init(dev_file_name); + string_t temp_str; + string_init(temp_str); + bool init = false; + + do { + // Create subghz folder directory if necessary + if(!file_worker_mkdir(instance->file_worker, SUBGHZ_RAW_FOLDER)) { + break; + } + // Create saved directory if necessary + if(!file_worker_mkdir(instance->file_worker, SUBGHZ_RAW_PATH_FOLDER)) { + break; + } + //get the name of the next free file + file_worker_get_next_filename( + instance->file_worker, + SUBGHZ_RAW_PATH_FOLDER, + dev_name, + SUBGHZ_APP_EXTENSION, + temp_str); + + string_set(instance->file_name, temp_str); + + string_printf( + dev_file_name, + "%s/%s%s", + SUBGHZ_RAW_PATH_FOLDER, + string_get_cstr(temp_str), + SUBGHZ_APP_EXTENSION); + // Open file + if(!file_worker_open( + instance->file_worker, + string_get_cstr(dev_file_name), + FSAM_WRITE, + FSOM_CREATE_ALWAYS)) { + break; + } + //Get string frequency preset protocol + string_printf( + temp_str, + "Frequency: %d\n" + "Preset: %d\n" + "Protocol: RAW\n", + (int)frequency, + (int)preset); + + if(!file_worker_write( + instance->file_worker, string_get_cstr(temp_str), string_size(temp_str))) { + break; + } + + instance->upload_raw = furi_alloc(SUBGHZ_DOWNLOAD_MAX_SIZE * sizeof(uint16_t)); + instance->file_is_open = RAWFileIsOpenWrite; + instance->sample_write = 0; + init = true; + } while(0); + + string_clear(temp_str); + string_clear(dev_file_name); + + return init; +} + +void subghz_protocol_save_raw_to_file_stop(SubGhzProtocolRAW* instance) { + furi_assert(instance); + + if(instance->file_is_open == RAWFileIsOpenWrite && instance->ind_write) + subghz_protocol_save_raw_to_file_write(instance); + if(instance->file_is_open != RAWFileIsOpenClose) { + free(instance->upload_raw); + instance->upload_raw = NULL; + } + + file_worker_close(instance->file_worker); + instance->file_is_open = RAWFileIsOpenClose; +} + +bool subghz_protocol_save_raw_to_file_write(SubGhzProtocolRAW* instance) { + furi_assert(instance); + + string_t temp_str; + string_init(temp_str); + bool is_write = false; + if(instance->file_is_open == RAWFileIsOpenWrite) { + do { + string_printf(temp_str, "RAW_Data: "); + + if(!file_worker_write( + instance->file_worker, string_get_cstr(temp_str), string_size(temp_str))) { + break; + } + + for(size_t i = 0; i < instance->ind_write - 1; i++) { + string_printf(temp_str, "%d, ", instance->upload_raw[i]); + if(!file_worker_write( + instance->file_worker, string_get_cstr(temp_str), string_size(temp_str))) { + break; + } + } + + string_printf(temp_str, "%d\n", instance->upload_raw[instance->ind_write - 1]); + if(!file_worker_write( + instance->file_worker, string_get_cstr(temp_str), string_size(temp_str))) { + break; + } + + instance->sample_write += instance->ind_write; + instance->ind_write = 0; + is_write = true; + } while(0); + string_clear(temp_str); + } + return is_write; +} + +size_t subghz_save_protocol_raw_get_sample_write(SubGhzProtocolRAW* instance) { + return instance->sample_write + instance->ind_write; +} + +bool subghz_protocol_raw_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolRAW* instance, + const char* file_path) { + subghz_protocol_set_last_file_name(instance, file_path); + return true; +} \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_raw.h b/lib/subghz/protocols/subghz_protocol_raw.h new file mode 100644 index 000000000..58253d013 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_raw.h @@ -0,0 +1,64 @@ +#pragma once + +#include "subghz_protocol_common.h" + +typedef struct SubGhzProtocolRAW SubGhzProtocolRAW; + +/** Allocate SubGhzProtocolRAW + * + * @return SubGhzProtocolRAW* + */ +SubGhzProtocolRAW* subghz_protocol_raw_alloc(); + +/** Free SubGhzProtocolRAW + * + * @param instance + */ +void subghz_protocol_raw_free(SubGhzProtocolRAW* instance); + +/** Reset internal state + * @param instance - SubGhzProtocolRAW instance + */ +void subghz_protocol_raw_reset(SubGhzProtocolRAW* instance); + +/** Get upload protocol + * + * @param instance - SubGhzProtocolRAW instance + * @param encoder - SubGhzProtocolCommonEncoder encoder + * @return bool + */ +bool subghz_protocol_raw_send_key( + SubGhzProtocolRAW* instance, + SubGhzProtocolCommonEncoder* encoder); + +/** Parse accepted duration + * + * @param instance - SubGhzProtocolRAW instance + * @param data - LevelDuration level_duration + */ +void subghz_protocol_raw_parse(SubGhzProtocolRAW* instance, bool level, uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolRAW* instance + * @param output - output string + */ +void subghz_protocol_raw_to_str(SubGhzProtocolRAW* instance, string_t output); + +const char* subghz_protocol_get_last_file_name(SubGhzProtocolRAW* instance); + +void subghz_protocol_set_last_file_name(SubGhzProtocolRAW* instance, const char* name); + +bool subghz_protocol_save_raw_to_file_init( + SubGhzProtocolRAW* instance, + const char* dev_name, + uint32_t frequency, + FuriHalSubGhzPreset preset); +void subghz_protocol_save_raw_to_file_stop(SubGhzProtocolRAW* instance); +bool subghz_protocol_save_raw_to_file_write(SubGhzProtocolRAW* instance); +size_t subghz_save_protocol_raw_get_sample_write(SubGhzProtocolRAW* instance); + +bool subghz_protocol_raw_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolRAW* instance, + const char* file_path); \ No newline at end of file diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c new file mode 100644 index 000000000..4f2aa0746 --- /dev/null +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -0,0 +1,210 @@ +#include "subghz_file_encoder_worker.h" +#include + +#include "file-worker.h" + +#define SUBGHZ_FILE_ENCODER_LOAD 512 + +struct SubGhzFileEncoderWorker { + FuriThread* thread; + StreamBufferHandle_t stream; + FileWorker* file_worker; + + volatile bool worker_running; + bool level; + int16_t duration; + string_t str_data; + string_t file_path; +}; + +void subghz_file_encoder_worker_add_livel_duration( + SubGhzFileEncoderWorker* instance, + int16_t duration) { + bool res = true; + if(duration < 0 && !instance->level) { + instance->duration += duration; + res = false; + } else if(duration > 0 && instance->level) { + instance->duration += duration; + res = false; + } else if(duration == 0) { + instance->duration = 0; + } + + if(res) { + instance->level = !instance->level; + instance->duration += duration; + xStreamBufferSend(instance->stream, &instance->duration, sizeof(int16_t), 10); + instance->duration = 0; + } +} + +bool subghz_file_encoder_worker_data_parse( + SubGhzFileEncoderWorker* instance, + const char* strStart, + size_t len) { + char* str1; + size_t ind_start = (size_t)strStart; //store the start address of the beginning of the line + bool res = false; + + str1 = strstr( + strStart, "RAW_Data: "); //looking for the beginning of the desired title in the line + if(str1 != NULL) { + str1 = strchr( + str1, + ' '); //if found, shift the pointer by 1 element per line "RAW_Data: -1, 2, -2..." + subghz_file_encoder_worker_add_livel_duration(instance, atoi(str1)); + while( + strchr(str1, ',') != NULL && + ((size_t)str1 < + (len + + ind_start))) { //check that there is still an element in the line and that it has not gone beyond the line + str1 = strchr(str1, ','); + str1 += 2; //if found, shift the pointer by next element per line + subghz_file_encoder_worker_add_livel_duration(instance, atoi(str1)); + } + res = true; + } + return res; +} + +LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { + furi_assert(context); + SubGhzFileEncoderWorker* instance = context; + int16_t duration; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + int ret = xStreamBufferReceiveFromISR( + instance->stream, &duration, sizeof(int16_t), &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + if(ret == sizeof(int16_t)) { + LevelDuration level_duration = {.level = LEVEL_DURATION_RESET}; + if(duration < 0) { + level_duration = level_duration_make(false, duration * -1); + } else if(duration > 0) { + level_duration = level_duration_make(true, duration); + } else if(duration == 0) { + level_duration = level_duration_reset(); + FURI_LOG_I("SubGhzFileEncoderWorker", "Stop transmission"); + } + return level_duration; + } else { + FURI_LOG_E("SubGhzFileEncoderWorker", "Slow flash read"); + return level_duration_wait(); + } +} + +/** Worker thread + * + * @param context + * @return exit code + */ +static int32_t subghz_file_encoder_worker_thread(void* context) { + SubGhzFileEncoderWorker* instance = context; + FURI_LOG_I("SubGhzFileEncoderWorker", "Worker start"); + bool res = false; + do { + if(!file_worker_open( + instance->file_worker, + string_get_cstr(instance->file_path), + FSAM_READ, + FSOM_OPEN_EXISTING)) { + break; + } + //todo skips 3 lines file header + if(!file_worker_read_until(instance->file_worker, instance->str_data, '\n')) { + break; + } + if(!file_worker_read_until(instance->file_worker, instance->str_data, '\n')) { + break; + } + if(!file_worker_read_until(instance->file_worker, instance->str_data, '\n')) { + break; + } + res = true; + FURI_LOG_I("SubGhzFileEncoderWorker", "Start transmission"); + } while(0); + + while(res && instance->worker_running) { + size_t stream_free_byte = xStreamBufferSpacesAvailable(instance->stream); + if((stream_free_byte / sizeof(int16_t)) >= SUBGHZ_FILE_ENCODER_LOAD) { + if(file_worker_read_until(instance->file_worker, instance->str_data, '\n')) { + if(!subghz_file_encoder_worker_data_parse( + instance, + string_get_cstr(instance->str_data), + strlen(string_get_cstr(instance->str_data)))) { + //to stop DMA correctly + subghz_file_encoder_worker_add_livel_duration(instance, LEVEL_DURATION_RESET); + subghz_file_encoder_worker_add_livel_duration(instance, LEVEL_DURATION_RESET); + + break; + } + } else { + subghz_file_encoder_worker_add_livel_duration(instance, LEVEL_DURATION_RESET); + subghz_file_encoder_worker_add_livel_duration(instance, LEVEL_DURATION_RESET); + break; + } + } + } + //waiting for the end of the transfer + while(instance->worker_running) { + osDelay(50); + } + file_worker_close(instance->file_worker); + FURI_LOG_I("SubGhzFileEncoderWorker", "Worker stop"); + return 0; +} + +SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { + SubGhzFileEncoderWorker* instance = furi_alloc(sizeof(SubGhzFileEncoderWorker)); + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "subghz_file_encoder_worker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_callback(instance->thread, subghz_file_encoder_worker_thread); + instance->stream = xStreamBufferCreate(sizeof(int16_t) * 4096, sizeof(int16_t)); + + instance->file_worker = file_worker_alloc(false); + string_init(instance->str_data); + string_init(instance->file_path); + instance->level = false; + + return instance; +} + +void subghz_file_encoder_worker_free(SubGhzFileEncoderWorker* instance) { + furi_assert(instance); + + vStreamBufferDelete(instance->stream); + furi_thread_free(instance->thread); + + string_clear(instance->str_data); + string_clear(instance->file_path); + file_worker_free(instance->file_worker); + + free(instance); +} + +bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path) { + furi_assert(instance); + furi_assert(!instance->worker_running); + + xStreamBufferReset(instance->stream); + string_set(instance->file_path, file_path); + instance->worker_running = true; + furi_thread_start(instance->thread); + return true; +} + +void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance) { + furi_assert(instance); + furi_assert(instance->worker_running); + + instance->worker_running = false; + furi_thread_join(instance->thread); +} + +bool subghz_file_encoder_worker_is_running(SubGhzFileEncoderWorker* instance) { + furi_assert(instance); + return instance->worker_running; +} diff --git a/lib/subghz/subghz_file_encoder_worker.h b/lib/subghz/subghz_file_encoder_worker.h new file mode 100644 index 000000000..0c014a0bc --- /dev/null +++ b/lib/subghz/subghz_file_encoder_worker.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +typedef struct SubGhzFileEncoderWorker SubGhzFileEncoderWorker; + +/** Allocate SubGhzFileEncoderWorker + * + * @return SubGhzFileEncoderWorker* + */ +SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc(); + +/** Free SubGhzFileEncoderWorker + * + * @param instance SubGhzFileEncoderWorker instance + */ +void subghz_file_encoder_worker_free(SubGhzFileEncoderWorker* instance); + +LevelDuration subghz_file_encoder_worker_get_level_duration(void* context); + +/** Start SubGhzFileEncoderWorker + * + * @param instance SubGhzFileEncoderWorker instance + * @return bool - true if ok + */ +bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path); + +/** Stop SubGhzFileEncoderWorker + * + * @param instance SubGhzFileEncoderWorker instance + */ +void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance); + +/** Check if worker is running + * + * @param instance SubGhzFileEncoderWorker instance + * @return bool - true if running + */ +bool subghz_file_encoder_worker_is_running(SubGhzFileEncoderWorker* instance); diff --git a/lib/subghz/subghz_parser.c b/lib/subghz/subghz_parser.c index faf0b6dd9..b2b11789e 100644 --- a/lib/subghz/subghz_parser.c +++ b/lib/subghz/subghz_parser.c @@ -16,6 +16,7 @@ #include "protocols/subghz_protocol_nero_radio.h" #include "protocols/subghz_protocol_scher_khan.h" #include "protocols/subghz_protocol_kia.h" +#include "protocols/subghz_protocol_raw.h" #include "subghz_keystore.h" @@ -38,6 +39,7 @@ typedef enum { SubGhzProtocolTypeNeroRadio, SubGhzProtocolTypeScherKhan, SubGhzProtocolTypeKIA, + SubGhzProtocolTypeRAW, SubGhzProtocolTypeMax, } SubGhzProtocolType; @@ -109,6 +111,8 @@ SubGhzParser* subghz_parser_alloc() { (SubGhzProtocolCommon*)subghz_protocol_scher_khan_alloc(); instance->protocols[SubGhzProtocolTypeKIA] = (SubGhzProtocolCommon*)subghz_protocol_kia_alloc(); + instance->protocols[SubGhzProtocolTypeRAW] = + (SubGhzProtocolCommon*)subghz_protocol_raw_alloc(); return instance; } @@ -143,6 +147,7 @@ void subghz_parser_free(SubGhzParser* instance) { subghz_protocol_scher_khan_free( (SubGhzProtocolScherKhan*)instance->protocols[SubGhzProtocolTypeScherKhan]); subghz_protocol_kia_free((SubGhzProtocolKIA*)instance->protocols[SubGhzProtocolTypeKIA]); + subghz_protocol_raw_free((SubGhzProtocolRAW*)instance->protocols[SubGhzProtocolTypeRAW]); subghz_keystore_free(instance->keystore); @@ -197,6 +202,11 @@ void subghz_parser_load_nice_flor_s_file(SubGhzParser* instance, const char* fil (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); } +void subghz_parser_load_came_atomo_file(SubGhzParser* instance, const char* file_name) { + subghz_protocol_came_atomo_name_file( + (SubGhzProtocolCameAtomo*)instance->protocols[SubGhzProtocolTypeCameAtomo], file_name); +} + void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name) { subghz_keystore_load(instance->keystore, file_name); } @@ -229,6 +239,12 @@ void subghz_parser_reset(SubGhzParser* instance) { subghz_protocol_scher_khan_reset( (SubGhzProtocolScherKhan*)instance->protocols[SubGhzProtocolTypeScherKhan]); subghz_protocol_kia_reset((SubGhzProtocolKIA*)instance->protocols[SubGhzProtocolTypeKIA]); + subghz_protocol_raw_reset((SubGhzProtocolRAW*)instance->protocols[SubGhzProtocolTypeRAW]); +} + +void subghz_parser_raw_parse(SubGhzParser* instance, bool level, uint32_t duration) { + subghz_protocol_raw_parse( + (SubGhzProtocolRAW*)instance->protocols[SubGhzProtocolTypeRAW], level, duration); } void subghz_parser_parse(SubGhzParser* instance, bool level, uint32_t duration) { diff --git a/lib/subghz/subghz_parser.h b/lib/subghz/subghz_parser.h index 69341c187..7e6c72b8c 100644 --- a/lib/subghz/subghz_parser.h +++ b/lib/subghz/subghz_parser.h @@ -3,7 +3,7 @@ #include "protocols/subghz_protocol_common.h" typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context); -typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon *parser, void* context); +typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon* parser, void* context); typedef struct SubGhzParser SubGhzParser; @@ -33,7 +33,10 @@ SubGhzProtocolCommon* subghz_parser_get_by_name(SubGhzParser* instance, const ch * @param callback - SubGhzProtocolTextCallback callback * @param context */ -void subghz_parser_enable_dump_text(SubGhzParser* instance, SubGhzProtocolTextCallback callback, void* context); +void subghz_parser_enable_dump_text( + SubGhzParser* instance, + SubGhzProtocolTextCallback callback, + void* context); /** Outputting data SubGhzParser from all parsers * @@ -41,7 +44,10 @@ void subghz_parser_enable_dump_text(SubGhzParser* instance, SubGhzProtocolTextCa * @param callback - SubGhzProtocolTextCallback callback * @param context */ -void subghz_parser_enable_dump(SubGhzParser* instance, SubGhzProtocolCommonCallbackDump callback, void* context); +void subghz_parser_enable_dump( + SubGhzParser* instance, + SubGhzProtocolCommonCallbackDump callback, + void* context); /** File name rainbow table Nice Flor-S * @@ -50,6 +56,13 @@ void subghz_parser_enable_dump(SubGhzParser* instance, SubGhzProtocolCommonCallb */ void subghz_parser_load_nice_flor_s_file(SubGhzParser* instance, const char* file_name); +/** File name rainbow table Came Atomo + * + * @param instance - SubGhzParser instance + * @param file_name - "path/file_name" + */ +void subghz_parser_load_came_atomo_file(SubGhzParser* instance, const char* file_name); + /** File upload manufacture keys * * @param instance - SubGhzParser instance @@ -63,6 +76,8 @@ void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_nam */ void subghz_parser_reset(SubGhzParser* instance); +void subghz_parser_raw_parse(SubGhzParser* instance, bool level, uint32_t duration); + /** Loading data into all parsers * * @param instance - SubGhzParser instance diff --git a/lib/toolbox/level_duration.h b/lib/toolbox/level_duration.h index 958c3890a..bef0b6eca 100644 --- a/lib/toolbox/level_duration.h +++ b/lib/toolbox/level_duration.h @@ -9,6 +9,7 @@ #define LEVEL_DURATION_RESET 0U #define LEVEL_DURATION_LEVEL_LOW 1U #define LEVEL_DURATION_LEVEL_HIGH 2U +#define LEVEL_DURATION_WAIT 3U #define LEVEL_DURATION_RESERVED 0x800000U typedef struct { @@ -29,10 +30,20 @@ static inline LevelDuration level_duration_reset() { return level_duration; } +static inline LevelDuration level_duration_wait() { + LevelDuration level_duration; + level_duration.level = LEVEL_DURATION_WAIT; + return level_duration; +} + static inline bool level_duration_is_reset(LevelDuration level_duration) { return level_duration.level == LEVEL_DURATION_RESET; } +static inline bool level_duration_is_wait(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_WAIT; +} + static inline bool level_duration_get_level(LevelDuration level_duration) { return level_duration.level == LEVEL_DURATION_LEVEL_HIGH; }