diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/subghz/helpers/subghz_custom_event.h index 5a423e6f..1d919b8c 100644 --- a/applications/subghz/helpers/subghz_custom_event.h +++ b/applications/subghz/helpers/subghz_custom_event.h @@ -14,8 +14,8 @@ typedef enum { SubghzCustomEventSceneShowError, SubghzCustomEventSceneShowOnlyRX, - SubghzCustomEventSceneNeedSavingNo, - SubghzCustomEventSceneNeedSavingYes, + SubghzCustomEventSceneExit, + SubghzCustomEventSceneStay, SubghzCustomEventViewReceverOK, SubghzCustomEventViewReceverConfig, @@ -25,7 +25,10 @@ typedef enum { SubghzCustomEventViewReadRAWIDLE, SubghzCustomEventViewReadRAWREC, SubghzCustomEventViewReadRAWConfig, - SubghzCustomEventViewReadRAWMore, + SubghzCustomEventViewReadRAWErase, + SubghzCustomEventViewReadRAWSendStart, + SubghzCustomEventViewReadRAWSendStop, + SubghzCustomEventViewReadRAWSave, SubghzCustomEventViewTransmitterBack, SubghzCustomEventViewTransmitterSendStart, diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index 6d89cb74..d0be3c00 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -18,5 +18,4 @@ ADD_SCENE(subghz, test_packet, TestPacket) ADD_SCENE(subghz, set_type, SetType) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, read_raw, ReadRAW) -ADD_SCENE(subghz, read_raw_menu, ReadRAWMenu) ADD_SCENE(subghz, need_saving, NeedSaving) \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_need_saving.c b/applications/subghz/scenes/subghz_scene_need_saving.c index c7f83ce0..b46b2450 100644 --- a/applications/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/subghz/scenes/subghz_scene_need_saving.c @@ -6,42 +6,46 @@ void subghz_scene_need_saving_callback(GuiButtonType result, InputType type, voi SubGhz* subghz = context; if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubghzCustomEventSceneNeedSavingYes); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneStay); } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubghzCustomEventSceneNeedSavingNo); + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneExit); } } void subghz_scene_need_saving_on_enter(void* context) { SubGhz* subghz = context; + widget_add_string_multiline_element( + subghz->widget, 64, 13, AlignCenter, AlignCenter, FontPrimary, "Exit to Gub-Ghz menu?"); widget_add_string_multiline_element( subghz->widget, 64, - 25, + 32, AlignCenter, AlignCenter, FontSecondary, - "There is an unsaved data.\nDo you want to save it?"); + "All unsaved will be\nlost."); widget_add_button_element( - subghz->widget, GuiButtonTypeRight, "Save", subghz_scene_need_saving_callback, subghz); + subghz->widget, GuiButtonTypeRight, "Stay", subghz_scene_need_saving_callback, subghz); widget_add_button_element( - subghz->widget, GuiButtonTypeLeft, "Delete", subghz_scene_need_saving_callback, subghz); + subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); } bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubghzCustomEventSceneNeedSavingYes) { - subghz->txrx->rx_key_state = SubGhzRxKeyStateNeedSave; + if(event.type == SceneManagerEventTypeBack) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + scene_manager_previous_scene(subghz->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzCustomEventSceneStay) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; scene_manager_previous_scene(subghz->scene_manager); return true; - } else if(event.event == SubghzCustomEventSceneNeedSavingNo) { + } else if(event.event == SubghzCustomEventSceneExit) { if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 7bf5576e..0bdd394c 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -2,6 +2,9 @@ #include "../views/subghz_read_raw.h" #include #include +#include + +#define RAW_FILE_NAME "Raw_temp" static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); @@ -27,13 +30,20 @@ void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) { view_dispatcher_send_custom_event(subghz->view_dispatcher, event); } +void subghz_scene_read_raw_callback_end_tx(void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventViewReadRAWSendStop); +} + void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateNeedSave) { - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubghzCustomEventViewReadRAWMore); + if(subghz->txrx->rx_key_state == SubGhzRxKeyStateBack) { + subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE); } else { + subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; } @@ -46,6 +56,11 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz_worker_set_pair_callback( subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_raw_parse); + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, + subghz_scene_read_raw_callback_end_tx, + subghz); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReadRAW); } @@ -54,20 +69,29 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubghzCustomEventViewReadRAWBack: + //Stop TX + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + subghz_sleep(subghz); + } + //Stop RX if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); }; - subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; - subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; + //Stop save file subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolRAW*)subghz->txrx->protocol_result); subghz->state_notifications = SubGhzNotificationStateIDLE; - - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + //needed save? + if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || + (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) { subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { + //Restore default setting + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } @@ -80,6 +104,63 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); return true; break; + case SubghzCustomEventViewReadRAWErase: + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + return true; + break; + case SubghzCustomEventViewReadRAWSendStart: + //set the path to read the file + if(strcmp( + subghz_protocol_raw_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result), + "")) { + string_t temp_str; + string_init_printf( + temp_str, + "%s", + subghz_protocol_raw_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); + path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); + strlcpy( + subghz->file_name, + string_get_cstr(temp_str), + strlen(string_get_cstr(temp_str)) + 1); + string_printf( + temp_str, + "%s/%s%s", + SUBGHZ_APP_PATH_FOLDER, + subghz->file_name, + SUBGHZ_APP_EXTENSION); + + subghz_protocol_raw_set_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); + string_clear(temp_str); + //start send + subghz->state_notifications = SubGhzNotificationStateIDLE; + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + } + if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || + (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { + if(!subghz_tx_start(subghz)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + } else { + subghz->state_notifications = SubGhzNotificationStateTX; + subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; + } + } + } + return true; + break; + case SubghzCustomEventViewReadRAWSendStop: + subghz->state_notifications = SubGhzNotificationStateIDLE; + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + subghz_sleep(subghz); + } + subghz_read_raw_stop_send(subghz->subghz_read_raw); + return true; + break; case SubghzCustomEventViewReadRAWIDLE: if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); @@ -101,7 +182,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_get_preset_name(subghz, subghz->error_str); if(subghz_protocol_raw_save_to_file_init( (SubGhzProtocolRAW*)subghz->txrx->protocol_result, - "Raw_temp", + RAW_FILE_NAME, subghz->txrx->frequency, string_get_cstr(subghz->error_str))) { if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || @@ -118,21 +199,25 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { return true; break; - case SubghzCustomEventViewReadRAWMore: + case SubghzCustomEventViewReadRAWSave: if(strcmp( subghz_protocol_raw_get_last_file_name( (SubGhzProtocolRAW*)subghz->txrx->protocol_result), "")) { - strlcpy( - subghz->file_name, - subghz_protocol_raw_get_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result), - strlen(subghz_protocol_raw_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", + subghz_protocol_raw_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); + path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); + strlcpy( + subghz->file_name, + string_get_cstr(temp_str), + strlen(string_get_cstr(temp_str)) + 1); + + //set the path to read the file + string_printf( temp_str, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, @@ -142,7 +227,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); string_clear(temp_str); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAWMenu); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); + subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } return true; break; @@ -160,6 +248,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi()); break; + case SubGhzNotificationStateTX: + notification_message(subghz->notifications, &sequence_blink_green_10); + subghz_read_raw_update_sin(subghz->subghz_read_raw); + break; default: break; } diff --git a/applications/subghz/scenes/subghz_scene_read_raw_menu.c b/applications/subghz/scenes/subghz_scene_read_raw_menu.c deleted file mode 100644 index 2c6deefc..00000000 --- a/applications/subghz/scenes/subghz_scene_read_raw_menu.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "../subghz_i.h" - -enum SubmenuIndex { - SubmenuIndexEmulate, - SubmenuIndexEdit, - SubmenuIndexDelete, -}; - -void subghz_scene_read_raw_menu_submenu_callback(void* context, uint32_t index) { - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, index); -} - -void subghz_scene_read_raw_menu_on_enter(void* context) { - SubGhz* subghz = context; - submenu_add_item( - subghz->submenu, - "Emulate", - SubmenuIndexEmulate, - subghz_scene_read_raw_menu_submenu_callback, - subghz); - - submenu_add_item( - subghz->submenu, - "Save", - SubmenuIndexEdit, - subghz_scene_read_raw_menu_submenu_callback, - subghz); - - submenu_add_item( - subghz->submenu, - "Delete", - SubmenuIndexDelete, - subghz_scene_read_raw_menu_submenu_callback, - subghz); - - submenu_set_selected_item( - subghz->submenu, - scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSavedMenu)); - - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); -} - -bool subghz_scene_read_raw_menu_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexEmulate) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAWMenu, SubmenuIndexEmulate); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); - return true; - } else if(event.event == SubmenuIndexDelete) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAWMenu, SubmenuIndexDelete); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDelete); - return true; - } else if(event.event == SubmenuIndexEdit) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAWMenu, SubghzCustomEventManagerSet); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - return true; - } - } - return false; -} - -void subghz_scene_read_raw_menu_on_exit(void* context) { - SubGhz* subghz = context; - submenu_clean(subghz->submenu); - subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; -} diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index d448119c..b86f9655 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -2,6 +2,7 @@ #include #include "file-worker.h" #include "../helpers/subghz_custom_event.h" +#include void subghz_scene_save_name_text_input_callback(void* context) { SubGhz* subghz = context; @@ -20,7 +21,7 @@ void subghz_scene_save_name_on_enter(void* context) { dev_name_empty = true; } else { memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name) + 1); - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAWMenu) == + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == SubghzCustomEventManagerSet) { subghz_get_next_name_file(subghz); } @@ -49,6 +50,11 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { subghz_save_protocol_to_file(subghz, subghz->file_name); } + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == + SubghzCustomEventManagerSet) { + subghz_protocol_raw_set_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name); + } subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); return true; @@ -68,5 +74,5 @@ void subghz_scene_save_name_on_exit(void* context) { // Clear view text_input_clean(subghz->text_input); scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAWMenu, SubghzCustomEventManagerNoSet); + subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); } diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index 31e7d3ee..7509abd8 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -26,8 +26,11 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(event.event == SubghzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneReadRAW)) { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + } } return true; } diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c index 3b5b5cd1..ecdfde12 100644 --- a/applications/subghz/scenes/subghz_scene_start.c +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -23,7 +23,7 @@ void subghz_scene_start_on_enter(void* context) { subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); submenu_add_item( subghz->submenu, - "Read Raw", + "Read RAW", SubmenuIndexReadRAW, subghz_scene_start_submenu_callback, subghz); @@ -57,6 +57,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index ef27721d..e459642d 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -70,6 +70,7 @@ typedef enum { SubGhzRxKeyStateIDLE, SubGhzRxKeyStateNoSave, SubGhzRxKeyStateNeedSave, + SubGhzRxKeyStateBack, SubGhzRxKeyStateAddKey, SubGhzRxKeyStateExit, } SubGhzRxKeyState; diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/subghz/views/subghz_read_raw.c index fb9d694b..b48c8e6f 100644 --- a/applications/subghz/views/subghz_read_raw.c +++ b/applications/subghz/views/subghz_read_raw.c @@ -11,13 +11,6 @@ #include #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100 -typedef enum { - SubghzReadRAWStatusStart, - SubghzReadRAWStatusIDLE, - SubghzReadRAWStatusREC, - //SubghzReadRAWStatusShowName, -} SubghzReadRAWStatus; - struct SubghzReadRAW { View* view; SubghzReadRAWCallback callback; @@ -31,6 +24,7 @@ typedef struct { uint8_t* rssi_history; bool rssi_history_end; uint8_t ind_write; + uint8_t ind_sin; SubghzReadRAWStatus satus; } SubghzReadRAWModel; @@ -89,6 +83,88 @@ void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample) }); } +void subghz_read_raw_stop_send(SubghzReadRAW* instance) { + furi_assert(instance); + + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + if(model->satus == SubghzReadRAWStatusTXRepeat) { + // Start TX + instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); + } else { + model->satus = SubghzReadRAWStatusIDLE; + } + return true; + }); +} + +void subghz_read_raw_update_sin(SubghzReadRAW* instance) { + furi_assert(instance); + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + if(model->ind_sin++ > 62) { + model->ind_sin = 0; + } + return true; + }); +} + +static int8_t subghz_read_raw_tab_sin(uint8_t x) { + const uint8_t tab_sin[64] = {0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, + 40, 43, 46, 49, 51, 54, 57, 60, 63, 65, 68, 71, 73, + 76, 78, 81, 83, 85, 88, 90, 92, 94, 96, 98, 100, 102, + 104, 106, 107, 109, 111, 112, 113, 115, 116, 117, 118, 120, 121, + 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127}; + + int8_t r = tab_sin[((x & 0x40) ? -x - 1 : x) & 0x3f]; + if(x & 0x80) return -r; + return r; +} + +void subghz_read_raw_draw_sin(Canvas* canvas, SubghzReadRAWModel* model) { +#define SUBGHZ_RAW_SIN_AMPLITUDE 11 + for(int i = 114; i > 0; i--) { + canvas_draw_line( + canvas, + i, + 32 - subghz_read_raw_tab_sin(i + model->ind_sin * 16) / SUBGHZ_RAW_SIN_AMPLITUDE, + i + 1, + 32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) / + SUBGHZ_RAW_SIN_AMPLITUDE); + canvas_draw_line( + canvas, + i + 1, + 32 - subghz_read_raw_tab_sin((i + model->ind_sin * 16)) / SUBGHZ_RAW_SIN_AMPLITUDE, + i + 2, + 32 + subghz_read_raw_tab_sin((i + model->ind_sin * 16 + 1) * 2) / + SUBGHZ_RAW_SIN_AMPLITUDE); + } +} + +void subghz_read_raw_draw_scale(Canvas* canvas, SubghzReadRAWModel* model) { +#define SUBGHZ_RAW_TOP_SCALE 14 +#define SUBGHZ_RAW_END_SCALE 115 + + if(model->rssi_history_end == false) { + for(int i = SUBGHZ_RAW_END_SCALE; i > 0; i -= 15) { + canvas_draw_line(canvas, i, SUBGHZ_RAW_TOP_SCALE, i, SUBGHZ_RAW_TOP_SCALE + 4); + canvas_draw_line(canvas, i - 5, SUBGHZ_RAW_TOP_SCALE, i - 5, SUBGHZ_RAW_TOP_SCALE + 2); + canvas_draw_line( + canvas, i - 10, SUBGHZ_RAW_TOP_SCALE, i - 10, SUBGHZ_RAW_TOP_SCALE + 2); + } + } else { + for(int i = SUBGHZ_RAW_END_SCALE - model->ind_write % 15; i > -15; i -= 15) { + canvas_draw_line(canvas, i, SUBGHZ_RAW_TOP_SCALE, i, SUBGHZ_RAW_TOP_SCALE + 4); + if(SUBGHZ_RAW_END_SCALE > i + 5) + canvas_draw_line( + canvas, i + 5, SUBGHZ_RAW_TOP_SCALE, i + 5, SUBGHZ_RAW_TOP_SCALE + 2); + if(SUBGHZ_RAW_END_SCALE > i + 10) + canvas_draw_line( + canvas, i + 10, SUBGHZ_RAW_TOP_SCALE, i + 10, SUBGHZ_RAW_TOP_SCALE + 2); + } + } +} + void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) { int ind = 0; int base = 0; @@ -134,17 +210,26 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { canvas, 126, 0, AlignRight, AlignTop, string_get_cstr(model->sample_write)); canvas_draw_line(canvas, 0, 14, 115, 14); - subghz_read_raw_draw_rssi(canvas, model); canvas_draw_line(canvas, 0, 48, 115, 48); canvas_draw_line(canvas, 115, 14, 115, 48); + subghz_read_raw_draw_scale(canvas, model); + + if((model->satus == SubghzReadRAWStatusTX) || (model->satus == SubghzReadRAWStatusTXRepeat)) { + subghz_read_raw_draw_sin(canvas, model); + } else { + subghz_read_raw_draw_rssi(canvas, model); + } if(model->satus == SubghzReadRAWStatusIDLE) { - elements_button_left(canvas, "Config"); - elements_button_center(canvas, "REC"); - elements_button_right(canvas, "More"); + elements_button_left(canvas, "Erase"); + elements_button_center(canvas, "Send"); + elements_button_right(canvas, "Save"); } else if(model->satus == SubghzReadRAWStatusStart) { elements_button_left(canvas, "Config"); elements_button_center(canvas, "REC"); + } else if( + (model->satus == SubghzReadRAWStatusTX) || (model->satus == SubghzReadRAWStatusTXRepeat)) { + elements_button_center(canvas, "Send"); } else { elements_button_center(canvas, "Stop"); } @@ -158,35 +243,83 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { furi_assert(context); SubghzReadRAW* instance = context; - if(event->key == InputKeyBack && event->type == InputTypeShort) { - instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); + if(event->key == InputKeyOk && event->type == InputTypePress) { + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + uint8_t ret = false; + if(model->satus == SubghzReadRAWStatusIDLE) { + // Start TX + instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); + model->satus = SubghzReadRAWStatusTXRepeat; + ret = true; + } else if(model->satus == SubghzReadRAWStatusTX) { + model->satus = SubghzReadRAWStatusTXRepeat; + } + return ret; + }); + } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + if(model->satus == SubghzReadRAWStatusTXRepeat) { + // Stop repeat TX + model->satus = SubghzReadRAWStatusTX; + } + return false; + }); + } else if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + if(model->satus == SubghzReadRAWStatusREC) { + //Stop REC + instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); + model->satus = SubghzReadRAWStatusIDLE; + } else { + //Exit + instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); + } + return true; + }); + } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { with_view_model( instance->view, (SubghzReadRAWModel * model) { - if(model->satus == SubghzReadRAWStatusIDLE || - model->satus == SubghzReadRAWStatusStart) { + if(model->satus == SubghzReadRAWStatusStart) { + //Config instance->callback(SubghzCustomEventViewReadRAWConfig, instance->context); } + + if(model->satus == SubghzReadRAWStatusIDLE) { + //Erase + model->satus = SubghzReadRAWStatusStart; + model->rssi_history_end = false; + model->ind_write = 0; + string_set(model->sample_write, "0 spl."); + instance->callback(SubghzCustomEventViewReadRAWErase, instance->context); + } return true; }); } else if(event->key == InputKeyRight && event->type == InputTypeShort) { with_view_model( instance->view, (SubghzReadRAWModel * model) { + //Save if(model->satus == SubghzReadRAWStatusIDLE) { - instance->callback(SubghzCustomEventViewReadRAWMore, instance->context); + instance->callback(SubghzCustomEventViewReadRAWSave, instance->context); } return true; }); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( instance->view, (SubghzReadRAWModel * model) { - if(model->satus == SubghzReadRAWStatusIDLE || - model->satus == SubghzReadRAWStatusStart) { + if(model->satus == SubghzReadRAWStatusStart) { + //Record instance->callback(SubghzCustomEventViewReadRAWREC, instance->context); model->satus = SubghzReadRAWStatusREC; model->ind_write = 0; model->rssi_history_end = false; - } else { + } else if( + (model->satus != SubghzReadRAWStatusTX) && + (model->satus != SubghzReadRAWStatusTXRepeat)) { + //Stop instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); model->satus = SubghzReadRAWStatusIDLE; } @@ -197,19 +330,29 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { return true; } +void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus satus) { + furi_assert(instance); + if(satus == SubghzReadRAWStatusStart) { + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + model->satus = SubghzReadRAWStatusStart; + model->rssi_history_end = false; + model->ind_write = 0; + string_set(model->sample_write, "0 spl."); + return true; + }); + } else if(satus == SubghzReadRAWStatusIDLE) { + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + model->satus = SubghzReadRAWStatusIDLE; + return true; + }); + } +} + void subghz_read_raw_enter(void* context) { furi_assert(context); - SubghzReadRAW* instance = context; - - with_view_model( - instance->view, (SubghzReadRAWModel * model) { - model->satus = SubghzReadRAWStatusStart; - model->rssi_history = furi_alloc(SUBGHZ_READ_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; - }); + //SubghzReadRAW* instance = context; } void subghz_read_raw_exit(void* context) { @@ -223,10 +366,6 @@ void subghz_read_raw_exit(void* context) { instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); model->satus = SubghzReadRAWStatusStart; } - string_reset(model->frequency_str); - string_reset(model->preset_str); - string_reset(model->sample_write); - free(model->rssi_history); return true; }); } @@ -248,6 +387,7 @@ SubghzReadRAW* subghz_read_raw_alloc() { string_init(model->frequency_str); string_init(model->preset_str); string_init(model->sample_write); + model->rssi_history = furi_alloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t)); return true; }); @@ -262,6 +402,7 @@ void subghz_read_raw_free(SubghzReadRAW* instance) { string_clear(model->frequency_str); string_clear(model->preset_str); string_clear(model->sample_write); + free(model->rssi_history); return true; }); view_free(instance->view); diff --git a/applications/subghz/views/subghz_read_raw.h b/applications/subghz/views/subghz_read_raw.h index d6a2337f..6e1f79da 100644 --- a/applications/subghz/views/subghz_read_raw.h +++ b/applications/subghz/views/subghz_read_raw.h @@ -7,6 +7,14 @@ typedef struct SubghzReadRAW SubghzReadRAW; typedef void (*SubghzReadRAWCallback)(SubghzCustomEvent event, void* context); +typedef enum { + SubghzReadRAWStatusStart, + SubghzReadRAWStatusIDLE, + SubghzReadRAWStatusREC, + SubghzReadRAWStatusTX, + SubghzReadRAWStatusTXRepeat, +} SubghzReadRAWStatus; + void subghz_read_raw_set_callback( SubghzReadRAW* subghz_read_raw, SubghzReadRAWCallback callback, @@ -23,6 +31,12 @@ void subghz_read_raw_add_data_statusbar( void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample); +void subghz_read_raw_stop_send(SubghzReadRAW* instance); + +void subghz_read_raw_update_sin(SubghzReadRAW* instance); + void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi); +void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus satus); + View* subghz_read_raw_get_view(SubghzReadRAW* subghz_static); diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index 276482ee..25fa3b7a 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -469,7 +469,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) { case FuriHalVersionRegionEuRu: //433,05..434,79; 868,15..868,55 if(!(value >= 433050000 && value <= 434790000) && - !(value >= 868150000 && value <= 8680550000)) { + !(value >= 868150000 && value <= 868550000)) { } else { txrx = true; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c index 276482ee..25fa3b7a 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -469,7 +469,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) { case FuriHalVersionRegionEuRu: //433,05..434,79; 868,15..868,55 if(!(value >= 433050000 && value <= 434790000) && - !(value >= 868150000 && value <= 8680550000)) { + !(value >= 868150000 && value <= 868550000)) { } else { txrx = true; } diff --git a/lib/subghz/protocols/subghz_protocol_raw.c b/lib/subghz/protocols/subghz_protocol_raw.c index b9b9c5bc..9f36cdce 100644 --- a/lib/subghz/protocols/subghz_protocol_raw.c +++ b/lib/subghz/protocols/subghz_protocol_raw.c @@ -17,6 +17,8 @@ struct SubGhzProtocolRAW { string_t file_name; size_t sample_write; bool last_level; + SubGhzProtocolRAWCallbackEnd callback_end; + void* context_end; }; typedef enum { @@ -65,6 +67,22 @@ void subghz_protocol_raw_free(SubGhzProtocolRAW* instance) { free(instance); } +void subghz_protocol_raw_file_encoder_worker_callback_end(void* context) { + furi_assert(context); + SubGhzProtocolRAW* instance = context; + if(instance->callback_end) instance->callback_end(instance->context_end); +} + +void subghz_protocol_raw_file_encoder_worker_set_callback_end( + SubGhzProtocolRAW* instance, + SubGhzProtocolRAWCallbackEnd callback_end, + void* context_end) { + furi_assert(instance); + furi_assert(callback_end); + instance->callback_end = callback_end; + instance->context_end = context_end; +} + void subghz_protocol_raw_file_encoder_worker_stop(void* context) { furi_assert(context); SubGhzProtocolRAW* instance = context; @@ -90,10 +108,17 @@ bool subghz_protocol_raw_send_key( //the worker needs a file in order to open and read part of the file osDelay(100); instance->file_is_open = RAWFileIsOpenRead; + //Forwarding UPLOAD to common encoder subghz_protocol_encoder_common_set_callback( encoder, subghz_file_encoder_worker_get_level_duration, instance->file_worker_encoder); + //forced stop of transmission subghz_protocol_encoder_common_set_callback_end( encoder, subghz_protocol_raw_file_encoder_worker_stop, instance); + //file transfer complete callback + subghz_file_encoder_worker_callback_end( + instance->file_worker_encoder, + subghz_protocol_raw_file_encoder_worker_callback_end, + instance); loaded = true; } else { @@ -187,7 +212,8 @@ bool subghz_protocol_raw_save_to_file_init( break; } - if(!flipper_file_write_string_cstr(instance->flipper_file, "Protocol", instance->common.name)) { + if(!flipper_file_write_string_cstr( + instance->flipper_file, "Protocol", instance->common.name)) { FURI_LOG_E(TAG, "Unable to add Protocol"); break; } diff --git a/lib/subghz/protocols/subghz_protocol_raw.h b/lib/subghz/protocols/subghz_protocol_raw.h index 59202b47..9a6f8b9d 100644 --- a/lib/subghz/protocols/subghz_protocol_raw.h +++ b/lib/subghz/protocols/subghz_protocol_raw.h @@ -2,6 +2,8 @@ #include "subghz_protocol_common.h" +typedef void (*SubGhzProtocolRAWCallbackEnd)(void* context); + typedef struct SubGhzProtocolRAW SubGhzProtocolRAW; /** Allocate SubGhzProtocolRAW @@ -16,6 +18,11 @@ SubGhzProtocolRAW* subghz_protocol_raw_alloc(); */ void subghz_protocol_raw_free(SubGhzProtocolRAW* instance); +void subghz_protocol_raw_file_encoder_worker_set_callback_end( + SubGhzProtocolRAW* instance, + SubGhzProtocolRAWCallbackEnd callback_end, + void* context_end); + /** Reset internal state * @param instance - SubGhzProtocolRAW instance */ diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 7bde91fa..8a18c8f0 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -16,12 +16,26 @@ struct SubGhzFileEncoderWorker { FlipperFile* flipper_file; volatile bool worker_running; + volatile bool worker_stoping; bool level; int32_t duration; string_t str_data; string_t file_path; + + SubGhzFileEncoderWorkerCallbackEnd callback_end; + void* context_end; }; +void subghz_file_encoder_worker_callback_end( + SubGhzFileEncoderWorker* instance, + SubGhzFileEncoderWorkerCallbackEnd callback_end, + void* context_end) { + furi_assert(instance); + furi_assert(callback_end); + instance->callback_end = callback_end; + instance->context_end = context_end; +} + void subghz_file_encoder_worker_add_livel_duration( SubGhzFileEncoderWorker* instance, int32_t duration) { @@ -89,6 +103,7 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { } else if(duration == 0) { level_duration = level_duration_reset(); FURI_LOG_I(TAG, "Stop transmission"); + instance->worker_stoping = true; } return level_duration; } else { @@ -111,9 +126,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { if(!flipper_file_open_existing( instance->flipper_file, string_get_cstr(instance->file_path))) { FURI_LOG_E( - TAG, - "Unable to open file for read: %s", - string_get_cstr(instance->file_path)); + TAG, "Unable to open file for read: %s", string_get_cstr(instance->file_path)); break; } if(!flipper_file_read_string(instance->flipper_file, "Protocol", instance->str_data)) { @@ -124,6 +137,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { //skip the end of the previous line "\n" storage_file_seek(file, 1, false); res = true; + instance->worker_stoping = false; FURI_LOG_I(TAG, "Start transmission"); } while(0); @@ -152,7 +166,11 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { } //waiting for the end of the transfer FURI_LOG_I(TAG, "End read file"); + while(instance->worker_running) { + if(instance->worker_stoping) { + if(instance->callback_end) instance->callback_end(instance->context_end); + } osDelay(50); } flipper_file_close(instance->flipper_file); @@ -177,6 +195,7 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { string_init(instance->str_data); string_init(instance->file_path); instance->level = false; + instance->worker_stoping = true; return instance; } diff --git a/lib/subghz/subghz_file_encoder_worker.h b/lib/subghz/subghz_file_encoder_worker.h index 0c014a0b..85d6d930 100644 --- a/lib/subghz/subghz_file_encoder_worker.h +++ b/lib/subghz/subghz_file_encoder_worker.h @@ -2,8 +2,20 @@ #include +typedef void (*SubGhzFileEncoderWorkerCallbackEnd)(void* context); + typedef struct SubGhzFileEncoderWorker SubGhzFileEncoderWorker; +/** End callback SubGhzWorker + * + * @param instance SubGhzFileEncoderWorker instance + * @param callback SubGhzFileEncoderWorkerCallbackEnd callback + */ +void subghz_file_encoder_worker_callback_end( + SubGhzFileEncoderWorker* instance, + SubGhzFileEncoderWorkerCallbackEnd callback_end, + void* context_end); + /** Allocate SubGhzFileEncoderWorker * * @return SubGhzFileEncoderWorker*