[FL-1758] SubGhz refactoring part 1 (#689)
* SubGhz: refactoring * WeGet: Add support for outputting formatted lines, events center button pressed, center button released * Variable Item: slightly changed the display of data on the screen * SubGhz: add show errors, add show preset, refactoring * SubGhz: refactoring transmitter * SubGhz: removed unused modules * SubGhz: Add FuriHalSubGhzPresetOok270Async setting menu * SubGhz: fix annotation * SubGhz: add support Nero Radio Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									fbccb9fbaf
								
							
						
					
					
						commit
						f385340b2e
					
				| @ -68,10 +68,10 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { | |||||||
|                 canvas_draw_str(canvas, 73, item_text_y, "<"); |                 canvas_draw_str(canvas, 73, item_text_y, "<"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             canvas_draw_str(canvas, 84, item_text_y, string_get_cstr(item->current_value_text)); |             canvas_draw_str(canvas, 80, item_text_y, string_get_cstr(item->current_value_text)); | ||||||
| 
 | 
 | ||||||
|             if(item->current_value_index < (item->values_count - 1)) { |             if(item->current_value_index < (item->values_count - 1)) { | ||||||
|                 canvas_draw_str(canvas, 113, item_text_y, ">"); |                 canvas_draw_str(canvas, 115, item_text_y, ">"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -235,6 +235,21 @@ void variable_item_list_free(VariableItemList* variable_item_list) { | |||||||
|     free(variable_item_list); |     free(variable_item_list); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void variable_item_list_clean(VariableItemList* variable_item_list) { | ||||||
|  |     furi_assert(variable_item_list); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         variable_item_list->view, (VariableItemListModel * model) { | ||||||
|  |             VariableItemArray_it_t it; | ||||||
|  |             for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it); | ||||||
|  |                 VariableItemArray_next(it)) { | ||||||
|  |                 string_clean(VariableItemArray_ref(it)->current_value_text); | ||||||
|  |             } | ||||||
|  |             VariableItemArray_clean(model->items); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| View* variable_item_list_get_view(VariableItemList* variable_item_list) { | View* variable_item_list_get_view(VariableItemList* variable_item_list) { | ||||||
|     furi_assert(variable_item_list); |     furi_assert(variable_item_list); | ||||||
|     return variable_item_list->view; |     return variable_item_list->view; | ||||||
|  | |||||||
| @ -18,6 +18,9 @@ VariableItemList* variable_item_list_alloc(); | |||||||
|  * @param variable_item_list VariableItemList instance |  * @param variable_item_list VariableItemList instance | ||||||
|  */ |  */ | ||||||
| void variable_item_list_free(VariableItemList* variable_item_list); | void variable_item_list_free(VariableItemList* variable_item_list); | ||||||
|  | 
 | ||||||
|  | void variable_item_list_clean(VariableItemList* variable_item_list); | ||||||
|  | 
 | ||||||
| View* variable_item_list_get_view(VariableItemList* variable_item_list); | View* variable_item_list_get_view(VariableItemList* variable_item_list); | ||||||
| 
 | 
 | ||||||
| /** Add item to VariableItemList
 | /** Add item to VariableItemList
 | ||||||
|  | |||||||
| @ -118,6 +118,20 @@ static void widget_add_element(Widget* widget, WidgetElement* element) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void widget_add_string_multi_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     Align horizontal, | ||||||
|  |     Align vertical, | ||||||
|  |     Font font, | ||||||
|  |     const char* text) { | ||||||
|  |     furi_assert(widget); | ||||||
|  |     WidgetElement* string_multi_element = | ||||||
|  |         widget_element_string_multi_create(x, y, horizontal, vertical, font, text); | ||||||
|  |     widget_add_element(widget, string_multi_element); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void widget_add_string_element( | void widget_add_string_element( | ||||||
|     Widget* widget, |     Widget* widget, | ||||||
|     uint8_t x, |     uint8_t x, | ||||||
|  | |||||||
| @ -26,6 +26,23 @@ void widget_clear(Widget* widget); | |||||||
|  */ |  */ | ||||||
| View* widget_get_view(Widget* widget); | View* widget_get_view(Widget* widget); | ||||||
| 
 | 
 | ||||||
|  | /** Add Multi String Element
 | ||||||
|  |  * @param widget Widget instance | ||||||
|  |  * @param x - x coordinate | ||||||
|  |  * @param y - y coordinate | ||||||
|  |  * @param horizontal - Align instance | ||||||
|  |  * @param vertical - Align instance | ||||||
|  |  * @param font Font instance | ||||||
|  |  */ | ||||||
|  | void widget_add_string_multi_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     Align horizontal, | ||||||
|  |     Align vertical, | ||||||
|  |     Font font, | ||||||
|  |     const char* text); | ||||||
|  | 
 | ||||||
| /** Add String Element
 | /** Add String Element
 | ||||||
|  * @param widget Widget instance |  * @param widget Widget instance | ||||||
|  * @param x - x coordinate |  * @param x - x coordinate | ||||||
|  | |||||||
| @ -30,7 +30,18 @@ static bool gui_button_input(InputEvent* event, WidgetElement* element) { | |||||||
|     GuiButtonModel* model = element->model; |     GuiButtonModel* model = element->model; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if((event->type == InputTypeShort) && model->callback) { |     if(model->callback == NULL) return consumed; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyOk && event->type == InputTypePress && | ||||||
|  |        model->button_type == GuiButtonTypeCenter) { | ||||||
|  |         model->callback(GuiButtonTypeCenterPress, model->context); | ||||||
|  |         consumed = true; | ||||||
|  |     } else if( | ||||||
|  |         event->key == InputKeyOk && event->type == InputTypeRelease && | ||||||
|  |         model->button_type == GuiButtonTypeCenter) { | ||||||
|  |         model->callback(GuiButtonTypeCenterRelease, model->context); | ||||||
|  |         consumed = true; | ||||||
|  |     } else if(event->type == InputTypeShort) { | ||||||
|         if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) { |         if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) { | ||||||
|             model->callback(model->button_type, model->context); |             model->callback(model->button_type, model->context); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -6,6 +6,8 @@ typedef enum { | |||||||
|     GuiButtonTypeLeft, |     GuiButtonTypeLeft, | ||||||
|     GuiButtonTypeCenter, |     GuiButtonTypeCenter, | ||||||
|     GuiButtonTypeRight, |     GuiButtonTypeRight, | ||||||
|  |     GuiButtonTypeCenterPress, | ||||||
|  |     GuiButtonTypeCenterRelease, | ||||||
| } GuiButtonType; | } GuiButtonType; | ||||||
| 
 | 
 | ||||||
| typedef void (*ButtonCallback)(GuiButtonType result, void* context); | typedef void (*ButtonCallback)(GuiButtonType result, void* context); | ||||||
| @ -28,6 +30,15 @@ struct WidgetElement { | |||||||
|     Widget* parent; |     Widget* parent; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* Create multi string element */ | ||||||
|  | WidgetElement* widget_element_string_multi_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     Align horizontal, | ||||||
|  |     Align vertical, | ||||||
|  |     Font font, | ||||||
|  |     const char* text); | ||||||
|  | 
 | ||||||
| /* Create string element */ | /* Create string element */ | ||||||
| WidgetElement* widget_element_string_create( | WidgetElement* widget_element_string_create( | ||||||
|     uint8_t x, |     uint8_t x, | ||||||
|  | |||||||
| @ -0,0 +1,67 @@ | |||||||
|  | #include "widget_element_i.h" | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t x; | ||||||
|  |     uint8_t y; | ||||||
|  |     Align horizontal; | ||||||
|  |     Align vertical; | ||||||
|  |     Font font; | ||||||
|  |     string_t text; | ||||||
|  | } GuiStringMultiModel; | ||||||
|  | 
 | ||||||
|  | static void gui_string_multi_draw(Canvas* canvas, WidgetElement* element) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     furi_assert(element); | ||||||
|  |     GuiStringMultiModel* model = element->model; | ||||||
|  | 
 | ||||||
|  |     if(string_size(model->text)) { | ||||||
|  |         canvas_set_font(canvas, model->font); | ||||||
|  |         elements_multiline_text_aligned( | ||||||
|  |             canvas, | ||||||
|  |             model->x, | ||||||
|  |             model->y, | ||||||
|  |             model->horizontal, | ||||||
|  |             model->vertical, | ||||||
|  |             string_get_cstr(model->text)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void gui_string_multi_free(WidgetElement* gui_string) { | ||||||
|  |     furi_assert(gui_string); | ||||||
|  | 
 | ||||||
|  |     GuiStringMultiModel* model = gui_string->model; | ||||||
|  |     string_clear(model->text); | ||||||
|  |     free(gui_string->model); | ||||||
|  |     free(gui_string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WidgetElement* widget_element_string_multi_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     Align horizontal, | ||||||
|  |     Align vertical, | ||||||
|  |     Font font, | ||||||
|  |     const char* text) { | ||||||
|  |     furi_assert(text); | ||||||
|  | 
 | ||||||
|  |     // Allocate and init model
 | ||||||
|  |     GuiStringMultiModel* model = furi_alloc(sizeof(GuiStringMultiModel)); | ||||||
|  |     model->x = x; | ||||||
|  |     model->y = y; | ||||||
|  |     model->horizontal = horizontal; | ||||||
|  |     model->vertical = vertical; | ||||||
|  |     model->font = font; | ||||||
|  |     string_init_set_str(model->text, text); | ||||||
|  | 
 | ||||||
|  |     // Allocate and init Element
 | ||||||
|  |     WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement)); | ||||||
|  |     gui_string->parent = NULL; | ||||||
|  |     gui_string->input = NULL; | ||||||
|  |     gui_string->draw = gui_string_multi_draw; | ||||||
|  |     gui_string->free = gui_string_multi_free; | ||||||
|  |     gui_string->model = model; | ||||||
|  | 
 | ||||||
|  |     return gui_string; | ||||||
|  | } | ||||||
| @ -1,10 +1,12 @@ | |||||||
| ADD_SCENE(subghz, start, Start) | ADD_SCENE(subghz, start, Start) | ||||||
| ADD_SCENE(subghz, receiver, Receiver) | ADD_SCENE(subghz, receiver, Receiver) | ||||||
|  | ADD_SCENE(subghz, receiver_config, ReceiverConfig) | ||||||
|  | ADD_SCENE(subghz, receiver_info, ReceiverInfo) | ||||||
| ADD_SCENE(subghz, save_name, SaveName) | ADD_SCENE(subghz, save_name, SaveName) | ||||||
| ADD_SCENE(subghz, save_success, SaveSuccess) | ADD_SCENE(subghz, save_success, SaveSuccess) | ||||||
| ADD_SCENE(subghz, saved, Saved) | ADD_SCENE(subghz, saved, Saved) | ||||||
| ADD_SCENE(subghz, transmitter, Transmitter) | ADD_SCENE(subghz, transmitter, Transmitter) | ||||||
| ADD_SCENE(subghz, no_man, NoMan) | ADD_SCENE(subghz, show_error, ShowError) | ||||||
| ADD_SCENE(subghz, test, Test) | ADD_SCENE(subghz, test, Test) | ||||||
| ADD_SCENE(subghz, test_static, TestStatic) | ADD_SCENE(subghz, test_static, TestStatic) | ||||||
| ADD_SCENE(subghz, test_carrier, TestCarrier) | ADD_SCENE(subghz, test_carrier, TestCarrier) | ||||||
|  | |||||||
| @ -1,21 +1,102 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_receiver.h" | #include "../views/subghz_receiver.h" | ||||||
| 
 | 
 | ||||||
|  | static void subghz_scene_receiver_update_statusbar(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     char frequency_str[20]; | ||||||
|  |     char preset_str[10]; | ||||||
|  |     string_t history_stat_str; | ||||||
|  |     string_init(history_stat_str); | ||||||
|  |     if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { | ||||||
|  |         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 == FuriHalSubGhzPreset2FSKAsync) { | ||||||
|  |             snprintf(preset_str, sizeof(preset_str), "FM"); | ||||||
|  |         } else { | ||||||
|  |             furi_check(0); | ||||||
|  |         } | ||||||
|  |         subghz_receiver_add_data_statusbar( | ||||||
|  |             subghz->subghz_receiver, frequency_str, preset_str, string_get_cstr(history_stat_str)); | ||||||
|  |     } else { | ||||||
|  |         subghz_receiver_add_data_statusbar( | ||||||
|  |             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); | ||||||
|  |         subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |     } | ||||||
|  |     string_clear(history_stat_str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) { | void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     string_t str_buff; | ||||||
|  |     string_init(str_buff); | ||||||
|  | 
 | ||||||
|  |     if(subghz_history_add_to_history( | ||||||
|  |            subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) { | ||||||
|  |         subghz_protocol_reset(subghz->txrx->protocol); | ||||||
|  |         string_clean(str_buff); | ||||||
|  |         subghz_history_get_text_item_menu( | ||||||
|  |             subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); | ||||||
|  |         subghz_receiver_add_item_to_menu( | ||||||
|  |             subghz->subghz_receiver, | ||||||
|  |             string_get_cstr(str_buff), | ||||||
|  |             subghz_history_get_type_protocol( | ||||||
|  |                 subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); | ||||||
|  |         subghz_scene_receiver_update_statusbar(subghz); | ||||||
|  |     } | ||||||
|  |     string_clear(str_buff); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const void subghz_scene_receiver_on_enter(void* context) { | const void subghz_scene_receiver_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     SubghzReceiver* subghz_receiver = subghz->subghz_receiver; |  | ||||||
| 
 | 
 | ||||||
|     subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz); |     string_t str_buff; | ||||||
|  |     string_init(str_buff); | ||||||
|  | 
 | ||||||
|  |     //Load history to receiver
 | ||||||
|  |     subghz_receiver_exit(subghz->subghz_receiver); | ||||||
|  |     for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { | ||||||
|  |         string_clean(str_buff); | ||||||
|  |         subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); | ||||||
|  |         subghz_receiver_add_item_to_menu( | ||||||
|  |             subghz->subghz_receiver, | ||||||
|  |             string_get_cstr(str_buff), | ||||||
|  |             subghz_history_get_type_protocol(subghz->txrx->history, i)); | ||||||
|  |     } | ||||||
|  |     string_clear(str_buff); | ||||||
|  |     subghz_scene_receiver_update_statusbar(subghz); | ||||||
|  |     subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); | ||||||
|  |     subghz_protocol_enable_dump( | ||||||
|  |         subghz->txrx->protocol, subghz_scene_add_to_history_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result, subghz->protocol); |  | ||||||
|     subghz_receiver_set_worker(subghz_receiver, subghz->worker); |  | ||||||
|     subghz->state_notifications = NOTIFICATION_RX_STATE; |     subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||||
|  |     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |         subghz_rx_end(subghz->txrx->worker); | ||||||
|  |         //subghz_sleep();
 | ||||||
|  |         subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |     }; | ||||||
|  |     if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { | ||||||
|  |         subghz_begin(subghz->txrx->preset); | ||||||
|  |         subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); | ||||||
|  |         subghz->txrx->txrx_state = SubGhzTxRxStateRx; | ||||||
|  |     } | ||||||
|  |     if(subghz->txrx->idx_menu_chosen != 0) { | ||||||
|  |         subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -24,51 +105,43 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubghzReceverEventSave: |  | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |  | ||||||
|             subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); |  | ||||||
|             subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); |  | ||||||
|             subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); |  | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |  | ||||||
|             return true; |  | ||||||
|             break; |  | ||||||
|         case SubghzReceverEventBack: |         case SubghzReceverEventBack: | ||||||
|             scene_manager_previous_scene(subghz->scene_manager); |             // Stop CC1101 Rx
 | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |                 subghz_rx_end(subghz->txrx->worker); | ||||||
|  |                 subghz_sleep(); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             }; | ||||||
|  |             subghz_history_clean(subghz->txrx->history); | ||||||
|  |             subghz->txrx->hopper_state = SubGhzHopperStateOFF; | ||||||
|  |             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||||
|  |             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|  |             subghz->txrx->idx_menu_chosen = 0; | ||||||
|  |             subghz_protocol_enable_dump(subghz->txrx->protocol, NULL, subghz); | ||||||
|  |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         case SubghzReceverEventSendStart: |         case SubghzReceverEventOK: | ||||||
|             subghz->state_notifications = NOTIFICATION_TX_STATE; |             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); | ||||||
|             subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); | ||||||
|             subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); |  | ||||||
|             subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); |  | ||||||
|             subghz_transmitter_tx_start(subghz); |  | ||||||
|             return true; |  | ||||||
|             break; |  | ||||||
|         case SubghzReceverEventSendStop: |  | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |  | ||||||
|             subghz_transmitter_tx_stop(subghz); |  | ||||||
|             return true; |  | ||||||
|             break; |  | ||||||
|         case SubghzReceverEventMain: |  | ||||||
|             subghz->state_notifications = NOTIFICATION_RX_STATE; |  | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         case SubghzReceverEventConfig: |         case SubghzReceverEventConfig: | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             return true; |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); | ||||||
|             break; |  | ||||||
|         case SubghzReceverEventSendHistoryFull: |  | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |  | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|  |         if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|  |             subghz_hopper_update(subghz->txrx); | ||||||
|  |             subghz_scene_receiver_update_statusbar(subghz); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         switch(subghz->state_notifications) { |         switch(subghz->state_notifications) { | ||||||
|         case NOTIFICATION_TX_STATE: |  | ||||||
|             notification_message(subghz->notifications, &sequence_blink_red_10); |  | ||||||
|             break; |  | ||||||
|         case NOTIFICATION_RX_STATE: |         case NOTIFICATION_RX_STATE: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|             break; |             break; | ||||||
|  | |||||||
							
								
								
									
										156
									
								
								applications/subghz/scenes/subghz_scene_receiver_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								applications/subghz/scenes/subghz_scene_receiver_config.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | |||||||
|  | #include "../subghz_i.h" | ||||||
|  | 
 | ||||||
|  | #define PRESET_COUNT 3 | ||||||
|  | const char* const preset_text[PRESET_COUNT] = { | ||||||
|  |     "AM270", | ||||||
|  |     "AM650", | ||||||
|  |     "FM", | ||||||
|  | }; | ||||||
|  | const uint32_t preset_value[PRESET_COUNT] = { | ||||||
|  |     FuriHalSubGhzPresetOok270Async, /** OOK, bandwidth 270kHz, asynchronous */ | ||||||
|  |     FuriHalSubGhzPresetOok650Async, /** OOK, bandwidth 650kHz, asynchronous */ | ||||||
|  |     FuriHalSubGhzPreset2FSKAsync, /** FM, asynchronous */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define HOPPING_COUNT 2 | ||||||
|  | const char* const hopping_text[HOPPING_COUNT] = { | ||||||
|  |     "OFF", | ||||||
|  |     "ON", | ||||||
|  | }; | ||||||
|  | const uint32_t hopping_value[HOPPING_COUNT] = { | ||||||
|  |     SubGhzHopperStateOFF, | ||||||
|  |     SubGhzHopperStateRunnig, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_scene_receiver_config_uint32_value_index( | ||||||
|  |     const uint32_t value, | ||||||
|  |     const uint32_t values[], | ||||||
|  |     uint8_t values_count) { | ||||||
|  |     int64_t last_value = INT64_MIN; | ||||||
|  |     uint8_t index = 0; | ||||||
|  |     for(uint8_t i = 0; i < values_count; i++) { | ||||||
|  |         if((value >= last_value) && (value <= values[i])) { | ||||||
|  |             index = i; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         last_value = values[i]; | ||||||
|  |     } | ||||||
|  |     return index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_scene_receiver_config_hopper_value_index( | ||||||
|  |     const uint32_t value, | ||||||
|  |     const uint32_t values[], | ||||||
|  |     uint8_t values_count, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     if(value == values[0]) { | ||||||
|  |         return 0; | ||||||
|  |     } else { | ||||||
|  |         variable_item_set_current_value_text( | ||||||
|  |             (VariableItem*)scene_manager_get_scene_state( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneReceiverConfig), | ||||||
|  |             " -----"); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { | ||||||
|  |     SubGhz* subghz = variable_item_get_context(item); | ||||||
|  |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|  | 
 | ||||||
|  |     if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { | ||||||
|  |         variable_item_set_current_value_text(item, subghz_frequencies_text[index]); | ||||||
|  |         subghz->txrx->frequency = subghz_frequencies[index]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_scene_receiver_config_set_preset(VariableItem* item) { | ||||||
|  |     SubGhz* subghz = variable_item_get_context(item); | ||||||
|  |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|  | 
 | ||||||
|  |     variable_item_set_current_value_text(item, preset_text[index]); | ||||||
|  |     subghz->txrx->preset = preset_value[index]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) { | ||||||
|  |     SubGhz* subghz = variable_item_get_context(item); | ||||||
|  |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|  | 
 | ||||||
|  |     variable_item_set_current_value_text(item, hopping_text[index]); | ||||||
|  |     if(hopping_value[index] == SubGhzHopperStateOFF) { | ||||||
|  |         variable_item_set_current_value_text( | ||||||
|  |             (VariableItem*)scene_manager_get_scene_state( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneReceiverConfig), | ||||||
|  |             subghz_frequencies_text[subghz_frequencies_433_92]); | ||||||
|  |         subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||||
|  |     } else { | ||||||
|  |         variable_item_set_current_value_text( | ||||||
|  |             (VariableItem*)scene_manager_get_scene_state( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneReceiverConfig), | ||||||
|  |             " -----"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_receiver_config_on_enter(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     VariableItem* item; | ||||||
|  |     uint8_t value_index; | ||||||
|  | 
 | ||||||
|  |     item = variable_item_list_add( | ||||||
|  |         subghz->variable_item_list, | ||||||
|  |         "Frequency:", | ||||||
|  |         subghz_frequencies_count, | ||||||
|  |         subghz_scene_receiver_config_set_frequency, | ||||||
|  |         subghz); | ||||||
|  |     value_index = subghz_scene_receiver_config_uint32_value_index( | ||||||
|  |         subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count); | ||||||
|  |     scene_manager_set_scene_state( | ||||||
|  |         subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); | ||||||
|  |     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]); | ||||||
|  | 
 | ||||||
|  |     item = variable_item_list_add( | ||||||
|  |         subghz->variable_item_list, | ||||||
|  |         "Modulation:", | ||||||
|  |         PRESET_COUNT, | ||||||
|  |         subghz_scene_receiver_config_set_preset, | ||||||
|  |         subghz); | ||||||
|  |     value_index = subghz_scene_receiver_config_uint32_value_index( | ||||||
|  |         subghz->txrx->preset, preset_value, PRESET_COUNT); | ||||||
|  |     variable_item_set_current_value_index(item, value_index); | ||||||
|  |     variable_item_set_current_value_text(item, preset_text[value_index]); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     //SubGhz* subghz = context;
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_receiver_config_on_exit(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     variable_item_list_clean(subghz->variable_item_list); | ||||||
|  | } | ||||||
							
								
								
									
										163
									
								
								applications/subghz/scenes/subghz_scene_receiver_info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								applications/subghz/scenes/subghz_scene_receiver_info.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | |||||||
|  | #include "../subghz_i.h" | ||||||
|  | 
 | ||||||
|  | void subghz_scene_receiver_info_callback(GuiButtonType result, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     view_dispatcher_send_custom_event(subghz->view_dispatcher, result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_scene_receiver_info_update_parser(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     subghz->txrx->protocol_result = subghz_protocol_get_by_name( | ||||||
|  |         subghz->txrx->protocol, | ||||||
|  |         subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||||
|  | 
 | ||||||
|  |     if(subghz->txrx->protocol_result->to_load_protocol != NULL) { | ||||||
|  |         subghz->txrx->protocol_result->to_load_protocol( | ||||||
|  |             subghz->txrx->protocol_result, | ||||||
|  |             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||||
|  |         subghz->txrx->frequency = | ||||||
|  |             subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||||
|  |         subghz->txrx->preset = | ||||||
|  |             subghz_history_get_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_receiver_info_on_enter(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     if(subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|  |         char buffer_str[16]; | ||||||
|  |         snprintf( | ||||||
|  |             buffer_str, | ||||||
|  |             sizeof(buffer_str), | ||||||
|  |             "%03ld.%02ld", | ||||||
|  |             subghz->txrx->frequency / 1000000 % 1000, | ||||||
|  |             subghz->txrx->frequency / 10000 % 100); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); | ||||||
|  |         if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || | ||||||
|  |            subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { | ||||||
|  |             snprintf(buffer_str, sizeof(buffer_str), "AM"); | ||||||
|  |         } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { | ||||||
|  |             snprintf(buffer_str, sizeof(buffer_str), "FM"); | ||||||
|  |         } else { | ||||||
|  |             furi_check(0); | ||||||
|  |         } | ||||||
|  |         widget_add_string_element( | ||||||
|  |             subghz->widget, 113, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); | ||||||
|  |         string_t text; | ||||||
|  |         string_init(text); | ||||||
|  |         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); | ||||||
|  |         widget_add_string_multi_element( | ||||||
|  |             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); | ||||||
|  |         string_clear(text); | ||||||
|  | 
 | ||||||
|  |         if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && | ||||||
|  |            strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { | ||||||
|  |             widget_add_button_element( | ||||||
|  |                 subghz->widget, | ||||||
|  |                 GuiButtonTypeRight, | ||||||
|  |                 "Save", | ||||||
|  |                 subghz_scene_receiver_info_callback, | ||||||
|  |                 subghz); | ||||||
|  |             widget_add_button_element( | ||||||
|  |                 subghz->widget, | ||||||
|  |                 GuiButtonTypeCenter, | ||||||
|  |                 "Send", | ||||||
|  |                 subghz_scene_receiver_info_callback, | ||||||
|  |                 subghz); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } else { | ||||||
|  |         widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == GuiButtonTypeCenterPress) { | ||||||
|  |             //CC1101 Stop RX -> Start TX
 | ||||||
|  |             subghz->state_notifications = NOTIFICATION_TX_STATE; | ||||||
|  |             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|  |                 subghz->txrx->hopper_state = SubGhzHopperStatePause; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |                 subghz_rx_end(subghz->txrx->worker); | ||||||
|  |                 //subghz_sleep();
 | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             } | ||||||
|  |             if(!subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { | ||||||
|  |                 subghz_tx_start(subghz); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateTx; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         } else if(event.event == GuiButtonTypeCenterRelease) { | ||||||
|  |             //CC1101 Stop Tx -> Start RX
 | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|  |                 subghz_tx_stop(subghz); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { | ||||||
|  |                 subghz_begin(subghz->txrx->preset); | ||||||
|  |                 subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateRx; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { | ||||||
|  |                 subghz->txrx->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |             } | ||||||
|  |             subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||||
|  |             return true; | ||||||
|  |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|  |             //CC1101 Stop RX -> Save
 | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|  |                 subghz->txrx->hopper_state = SubGhzHopperStateOFF; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |                 subghz_rx_end(subghz->txrx->worker); | ||||||
|  |                 subghz_sleep(); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             } | ||||||
|  |             if(!subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && | ||||||
|  |                strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { | ||||||
|  |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|  |         if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|  |             subghz_hopper_update(subghz->txrx); | ||||||
|  |         } | ||||||
|  |         switch(subghz->state_notifications) { | ||||||
|  |         case NOTIFICATION_TX_STATE: | ||||||
|  |             notification_message(subghz->notifications, &sequence_blink_red_10); | ||||||
|  |             break; | ||||||
|  |         case NOTIFICATION_RX_STATE: | ||||||
|  |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_receiver_info_on_exit(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     widget_clear(subghz->widget); | ||||||
|  | } | ||||||
| @ -35,11 +35,13 @@ const bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent even | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { |         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { | ||||||
|             if(subghz_save_protocol_to_file(subghz, subghz->text_store)) { |             if(strcmp(subghz->text_store, "") && | ||||||
|  |                subghz_save_protocol_to_file(subghz, subghz->text_store)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); | ||||||
|                 return true; |                 return true; | ||||||
|             } else { |             } else { | ||||||
|                 //Error save
 |                 string_set(subghz->error_str, "No name file"); | ||||||
|  |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -8,15 +8,18 @@ enum SubmenuIndex { | |||||||
|     SubmenuIndexCAME12bit, |     SubmenuIndexCAME12bit, | ||||||
|     SubmenuIndexCAME24bit, |     SubmenuIndexCAME24bit, | ||||||
|     SubmenuIndexNeroSketch, |     SubmenuIndexNeroSketch, | ||||||
|  |     SubmenuIndexNeroRadio, | ||||||
|     SubmenuIndexGateTX, |     SubmenuIndexGateTX, | ||||||
|     SubmenuIndexDoorHan, |     SubmenuIndexDoorHan, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { | bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz->protocol_result = subghz_protocol_get_by_name(subghz->protocol, protocol_name); |     subghz->txrx->protocol_result = | ||||||
|     if(subghz->protocol_result == NULL) { |         subghz_protocol_get_by_name(subghz->txrx->protocol, protocol_name); | ||||||
|         //show error
 |     if(subghz->txrx->protocol_result == NULL) { | ||||||
|  |         string_set(subghz->error_str, "Protocol not found"); | ||||||
|  |         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
| @ -62,6 +65,8 @@ const void subghz_scene_set_type_on_enter(void* context) { | |||||||
|         subghz); |         subghz); | ||||||
|     // submenu_add_item(
 |     // submenu_add_item(
 | ||||||
|     //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
 |     //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
 | ||||||
|  |     // submenu_add_item(
 | ||||||
|  |     //     subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "Gate TX_433", |         "Gate TX_433", | ||||||
| @ -90,81 +95,86 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event | |||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubmenuIndexPricenton: |         case SubmenuIndexPricenton: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 24; |                 subghz->txrx->protocol_result->code_last_count_bit = 24; | ||||||
|                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->code_last_found = key; |                 subghz->txrx->protocol_result->code_last_found = key; | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexNiceFlo12bit: |         case SubmenuIndexNiceFlo12bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 12; |                 subghz->txrx->protocol_result->code_last_count_bit = 12; | ||||||
|                 key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 |                 key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | ||||||
|                 subghz->protocol_result->code_last_found = key; |                 subghz->txrx->protocol_result->code_last_found = key; | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexNiceFlo24bit: |         case SubmenuIndexNiceFlo24bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 24; |                 subghz->txrx->protocol_result->code_last_count_bit = 24; | ||||||
|                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->code_last_found = key; |                 subghz->txrx->protocol_result->code_last_found = key; | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexCAME12bit: |         case SubmenuIndexCAME12bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 12; |                 subghz->txrx->protocol_result->code_last_count_bit = 12; | ||||||
|                 key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 |                 key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | ||||||
|                 subghz->protocol_result->code_last_found = key; |                 subghz->txrx->protocol_result->code_last_found = key; | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexCAME24bit: |         case SubmenuIndexCAME24bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 24; |                 subghz->txrx->protocol_result->code_last_count_bit = 24; | ||||||
|                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |                 key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->code_last_found = key; |                 subghz->txrx->protocol_result->code_last_found = key; | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         // case SubmenuIndexNeroSketch:
 |         // case SubmenuIndexNeroSketch:
 | ||||||
|         //     /* code */
 |         //     /* code */
 | ||||||
|         //     break;
 |         //     break;
 | ||||||
|  |         // case SubmenuIndexNeroRadio:
 | ||||||
|  |         //     /* code */
 | ||||||
|  |         //     break;
 | ||||||
|         case SubmenuIndexGateTX: |         case SubmenuIndexGateTX: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 24; |                 subghz->txrx->protocol_result->code_last_count_bit = 24; | ||||||
|                 key = (key & 0x00F0FFFF) | 0xF << 16; //btn 0xF, 0xC, 0xA, 0x6
 |                 key = (key & 0x00F0FFFF) | 0xF << 16; //btn 0xF, 0xC, 0xA, 0x6
 | ||||||
|                 subghz->protocol_result->code_last_found = subghz_protocol_common_reverse_key( |                 subghz->txrx->protocol_result->code_last_found = | ||||||
|                     key, subghz->protocol_result->code_last_count_bit); |                     subghz_protocol_common_reverse_key( | ||||||
|  |                         key, subghz->txrx->protocol_result->code_last_count_bit); | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexDoorHan: |         case SubmenuIndexDoorHan: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) { |             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) { | ||||||
|                 subghz->protocol_result->code_last_count_bit = 64; |                 subghz->txrx->protocol_result->code_last_count_bit = 64; | ||||||
|                 subghz->protocol_result->serial = key & 0x0FFFFFFF; |                 subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF; | ||||||
|                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 |                 subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->cnt = 0x0003; |                 subghz->txrx->protocol_result->cnt = 0x0003; | ||||||
|                 if(subghz_protocol_keeloq_set_manufacture_name( |                 if(subghz_protocol_keeloq_set_manufacture_name( | ||||||
|                        subghz->protocol_result, "DoorHan")) { |                        subghz->txrx->protocol_result, "DoorHan")) { | ||||||
|                     subghz->protocol_result->code_last_found = |                     subghz->txrx->protocol_result->code_last_found = | ||||||
|                         subghz_protocol_keeloq_gen_key(subghz->protocol_result); |                         subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result); | ||||||
|                     generated_protocol = true; |                     generated_protocol = true; | ||||||
|                 } else { |                 } else { | ||||||
|                     generated_protocol = false; |                     generated_protocol = false; | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan); |                     string_set(subghz->error_str, "No manufactory key"); | ||||||
|  |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| 
 |  | ||||||
|         default: |         default: | ||||||
|             return false; |             return false; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         if(generated_protocol) { |         if(generated_protocol) { | ||||||
|             subghz->frequency = subghz_frequencies[subghz_frequencies_433_92]; |             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||||
|             subghz->preset = FuriHalSubGhzPresetOok650Async; |             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -2,26 +2,26 @@ | |||||||
| 
 | 
 | ||||||
| #define SCENE_NO_MAN_CUSTOM_EVENT (11UL) | #define SCENE_NO_MAN_CUSTOM_EVENT (11UL) | ||||||
| 
 | 
 | ||||||
| void subghz_scene_no_man_popup_callback(void* context) { | void subghz_scene_show_error_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = 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, SCENE_NO_MAN_CUSTOM_EVENT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const void subghz_scene_no_man_on_enter(void* context) { | const void subghz_scene_show_error_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = subghz->popup; |     Popup* popup = subghz->popup; | ||||||
|     popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); |     popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); | ||||||
|     popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom); |     popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom); | ||||||
|     popup_set_timeout(popup, 1500); |     popup_set_timeout(popup, 1500); | ||||||
|     popup_set_context(popup, subghz); |     popup_set_context(popup, subghz); | ||||||
|     popup_set_callback(popup, subghz_scene_no_man_popup_callback); |     popup_set_callback(popup, subghz_scene_show_error_popup_callback); | ||||||
|     popup_enable_timeout(popup); |     popup_enable_timeout(popup); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) { | const bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { |         if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { | ||||||
| @ -33,7 +33,7 @@ const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) | |||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const void subghz_scene_no_man_on_exit(void* context) { | const void subghz_scene_show_error_on_exit(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
| @ -45,4 +45,5 @@ const void subghz_scene_no_man_on_exit(void* context) { | |||||||
|     popup_set_context(popup, NULL); |     popup_set_context(popup, NULL); | ||||||
|     popup_set_timeout(popup, 0); |     popup_set_timeout(popup, 0); | ||||||
|     popup_disable_timeout(popup); |     popup_disable_timeout(popup); | ||||||
|  |     string_clean(subghz->error_str); | ||||||
| } | } | ||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_transmitter.h" | #include "../views/subghz_transmitter.h" | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||||
| 
 | 
 | ||||||
| void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) { | void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -7,42 +8,90 @@ void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* conte | |||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void subghz_scene_transmitter_update_data_show(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { | ||||||
|  |         string_t key_str; | ||||||
|  |         string_init(key_str); | ||||||
|  |         char frequency_str[10]; | ||||||
|  |         char preset_str[6]; | ||||||
|  |         uint8_t show_button = 0; | ||||||
|  |         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str); | ||||||
|  | 
 | ||||||
|  |         if((!strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) && | ||||||
|  |            (!strcmp( | ||||||
|  |                subghz_protocol_keeloq_get_manufacture_name(subghz->txrx->protocol_result), | ||||||
|  |                "Unknown"))) { | ||||||
|  |             show_button = 0; | ||||||
|  |         } else { | ||||||
|  |             show_button = 1; | ||||||
|  |         } | ||||||
|  |         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 == FuriHalSubGhzPreset2FSKAsync) { | ||||||
|  |             snprintf(preset_str, sizeof(preset_str), "FM"); | ||||||
|  |         } else { | ||||||
|  |             furi_check(0); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         subghz_transmitter_add_data_to_show( | ||||||
|  |             subghz->subghz_transmitter, | ||||||
|  |             string_get_cstr(key_str), | ||||||
|  |             frequency_str, | ||||||
|  |             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); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const void subghz_scene_transmitter_on_enter(void* context) { | const void subghz_scene_transmitter_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; |     subghz_transmitter_set_callback( | ||||||
| 
 |         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||||
|     subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); |     subghz_scene_transmitter_update_data_show(subghz); | ||||||
|     subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); |  | ||||||
|     subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); |  | ||||||
| 
 |  | ||||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; |     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 |  | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzTransmitterEventSendStart) { |         if(event.event == SubghzTransmitterEventSendStart) { | ||||||
|             subghz->state_notifications = NOTIFICATION_TX_STATE; |             subghz->state_notifications = NOTIFICATION_TX_STATE; | ||||||
|             subghz_transmitter_tx_start(subghz); |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |                 subghz_rx_end(subghz->txrx->worker); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             } | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { | ||||||
|  |                 subghz_tx_start(subghz); | ||||||
|  |                 subghz_scene_transmitter_update_data_show(subghz); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateTx; | ||||||
|  |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzTransmitterEventSendStop) { |         } else if(event.event == SubghzTransmitterEventSendStop) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             subghz_transmitter_tx_stop(subghz); |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|             subghz_sleep(); |                 subghz_tx_stop(subghz); | ||||||
|  |                 subghz_sleep(); | ||||||
|  |                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzTransmitterEventBack) { |         } else if(event.event == SubghzTransmitterEventBack) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             scene_manager_search_and_switch_to_previous_scene( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart); |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzTransmitterEventNoMan) { |  | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |  | ||||||
|             scene_manager_search_and_switch_to_previous_scene( |  | ||||||
|                 subghz->scene_manager, SubGhzSceneNoMan); |  | ||||||
|             return true; |  | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { |         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { | ||||||
| @ -55,7 +104,6 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev | |||||||
| 
 | 
 | ||||||
| const void subghz_scene_transmitter_on_exit(void* context) { | const void subghz_scene_transmitter_on_exit(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; | 
 | ||||||
|     subghz_transmitter_set_callback(subghz_transmitter, NULL, subghz); |  | ||||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; |     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,22 @@ | |||||||
| #include "subghz_i.h" | #include "subghz_i.h" | ||||||
| 
 | 
 | ||||||
|  | const char* const subghz_frequencies_text[] = { | ||||||
|  |     "300.00", | ||||||
|  |     "315.00", | ||||||
|  |     "348.00", | ||||||
|  |     "387.00", | ||||||
|  |     "433.08", | ||||||
|  |     "433.92", | ||||||
|  |     "434.78", | ||||||
|  |     "438.90", | ||||||
|  |     "464.00", | ||||||
|  |     "779.00", | ||||||
|  |     "868.35", | ||||||
|  |     "915.00", | ||||||
|  |     "925.00", | ||||||
|  |     "928.00", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| const uint32_t subghz_frequencies[] = { | const uint32_t subghz_frequencies[] = { | ||||||
|     /* 300 - 348 */ |     /* 300 - 348 */ | ||||||
|     300000000, |     300000000, | ||||||
| @ -20,7 +37,15 @@ const uint32_t subghz_frequencies[] = { | |||||||
|     928000000, |     928000000, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | const uint32_t subghz_hopper_frequencies[] = { | ||||||
|  |     315000000, | ||||||
|  |     433920000, | ||||||
|  |     868350000, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); | const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); | ||||||
|  | const uint32_t subghz_hopper_frequencies_count = | ||||||
|  |     sizeof(subghz_hopper_frequencies) / sizeof(uint32_t); | ||||||
| const uint32_t subghz_frequencies_433_92 = 5; | const uint32_t subghz_frequencies_433_92 = 5; | ||||||
| 
 | 
 | ||||||
| bool subghz_custom_event_callback(void* context, uint32_t event) { | bool subghz_custom_event_callback(void* context, uint32_t event) { | ||||||
| @ -77,11 +102,6 @@ SubGhz* subghz_alloc() { | |||||||
|         SubGhzViewReceiver, |         SubGhzViewReceiver, | ||||||
|         subghz_receiver_get_view(subghz->subghz_receiver)); |         subghz_receiver_get_view(subghz->subghz_receiver)); | ||||||
| 
 | 
 | ||||||
|     // Dialog
 |  | ||||||
|     subghz->dialog_ex = dialog_ex_alloc(); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         subghz->view_dispatcher, SubGhzViewDialogEx, dialog_ex_get_view(subghz->dialog_ex)); |  | ||||||
| 
 |  | ||||||
|     // Popup
 |     // Popup
 | ||||||
|     subghz->popup = popup_alloc(); |     subghz->popup = popup_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -92,6 +112,11 @@ SubGhz* subghz_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input)); |         subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input)); | ||||||
| 
 | 
 | ||||||
|  |     // Custom Widget
 | ||||||
|  |     subghz->widget = widget_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); | ||||||
|  | 
 | ||||||
|     // Transmitter
 |     // Transmitter
 | ||||||
|     subghz->subghz_transmitter = subghz_transmitter_alloc(); |     subghz->subghz_transmitter = subghz_transmitter_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -99,6 +124,13 @@ SubGhz* subghz_alloc() { | |||||||
|         SubGhzViewTransmitter, |         SubGhzViewTransmitter, | ||||||
|         subghz_transmitter_get_view(subghz->subghz_transmitter)); |         subghz_transmitter_get_view(subghz->subghz_transmitter)); | ||||||
| 
 | 
 | ||||||
|  |     // Variable Item List
 | ||||||
|  |     subghz->variable_item_list = variable_item_list_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         subghz->view_dispatcher, | ||||||
|  |         SubGhzViewVariableItemList, | ||||||
|  |         variable_item_list_get_view(subghz->variable_item_list)); | ||||||
|  | 
 | ||||||
|     // Carrier Test Module
 |     // Carrier Test Module
 | ||||||
|     subghz->subghz_test_carrier = subghz_test_carrier_alloc(); |     subghz->subghz_test_carrier = subghz_test_carrier_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -120,17 +152,26 @@ SubGhz* subghz_alloc() { | |||||||
|         SubGhzViewStatic, |         SubGhzViewStatic, | ||||||
|         subghz_test_static_get_view(subghz->subghz_test_static)); |         subghz_test_static_get_view(subghz->subghz_test_static)); | ||||||
| 
 | 
 | ||||||
|     //init Worker & Protocol
 |     //init Worker & Protocol & History
 | ||||||
|     subghz->worker = subghz_worker_alloc(); |     subghz->txrx = furi_alloc(sizeof(SubGhzTxRx)); | ||||||
|     subghz->protocol = subghz_protocol_alloc(); |     subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||||
|  |     subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|  |     subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |     subghz->txrx->hopper_state = SubGhzHopperStateOFF; | ||||||
|  |     subghz->txrx->history = subghz_history_alloc(); | ||||||
|  |     subghz->txrx->worker = subghz_worker_alloc(); | ||||||
|  |     subghz->txrx->protocol = subghz_protocol_alloc(); | ||||||
|     subghz_worker_set_overrun_callback( |     subghz_worker_set_overrun_callback( | ||||||
|         subghz->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); |         subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); | ||||||
|     subghz_worker_set_pair_callback( |     subghz_worker_set_pair_callback( | ||||||
|         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); |         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); | ||||||
|     subghz_worker_set_context(subghz->worker, subghz->protocol); |     subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->protocol); | ||||||
| 
 | 
 | ||||||
|     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes"); |     //Init Error_str
 | ||||||
|     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx"); |     string_init(subghz->error_str); | ||||||
|  | 
 | ||||||
|  |     subghz_protocol_load_keeloq_file(subghz->txrx->protocol, "/ext/subghz/keeloq_mfcodes"); | ||||||
|  |     subghz_protocol_load_nice_flor_s_file(subghz->txrx->protocol, "/ext/subghz/nice_floor_s_rx"); | ||||||
| 
 | 
 | ||||||
|     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 |     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 | ||||||
| 
 | 
 | ||||||
| @ -160,18 +201,22 @@ void subghz_free(SubGhz* subghz) { | |||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); | ||||||
|     text_input_free(subghz->text_input); |     text_input_free(subghz->text_input); | ||||||
| 
 | 
 | ||||||
|     // Receiver
 |     // Custom Widget
 | ||||||
|  |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); | ||||||
|  |     widget_free(subghz->widget); | ||||||
|  | 
 | ||||||
|  |     // Transmitter
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||||
|     subghz_transmitter_free(subghz->subghz_transmitter); |     subghz_transmitter_free(subghz->subghz_transmitter); | ||||||
| 
 | 
 | ||||||
|  |     // Variable Item List
 | ||||||
|  |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList); | ||||||
|  |     variable_item_list_free(subghz->variable_item_list); | ||||||
|  | 
 | ||||||
|     // Submenu
 |     // Submenu
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); | ||||||
|     submenu_free(subghz->submenu); |     submenu_free(subghz->submenu); | ||||||
| 
 | 
 | ||||||
|     // DialogEx
 |  | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewDialogEx); |  | ||||||
|     dialog_ex_free(subghz->dialog_ex); |  | ||||||
| 
 |  | ||||||
|     // Popup
 |     // Popup
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); | ||||||
|     popup_free(subghz->popup); |     popup_free(subghz->popup); | ||||||
| @ -186,9 +231,14 @@ void subghz_free(SubGhz* subghz) { | |||||||
|     furi_record_close("gui"); |     furi_record_close("gui"); | ||||||
|     subghz->gui = NULL; |     subghz->gui = NULL; | ||||||
| 
 | 
 | ||||||
|     //Worker & Protocol
 |     //Worker & Protocol & History
 | ||||||
|     subghz_protocol_free(subghz->protocol); |     subghz_protocol_free(subghz->txrx->protocol); | ||||||
|     subghz_worker_free(subghz->worker); |     subghz_worker_free(subghz->txrx->worker); | ||||||
|  |     subghz_history_free(subghz->txrx->history); | ||||||
|  |     free(subghz->txrx); | ||||||
|  | 
 | ||||||
|  |     //Error string
 | ||||||
|  |     string_clear(subghz->error_str); | ||||||
| 
 | 
 | ||||||
|     // Notifications
 |     // Notifications
 | ||||||
|     furi_record_close("notification"); |     furi_record_close("notification"); | ||||||
|  | |||||||
| @ -128,21 +128,27 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { | bool subghz_history_add_to_history( | ||||||
|  |     SubGhzHistory* instance, | ||||||
|  |     void* context, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhzProtocolCommon* protocol = context; |     SubGhzProtocolCommon* protocol = context; | ||||||
| 
 | 
 | ||||||
|     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return; |     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; | ||||||
|     if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) && |     if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) && | ||||||
|        ((millis() - instance->last_update_timestamp) < 500)) { |        ((millis() - instance->last_update_timestamp) < 500)) { | ||||||
|         instance->last_update_timestamp = millis(); |         instance->last_update_timestamp = millis(); | ||||||
|         return; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; |     instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; | ||||||
|     instance->last_update_timestamp = millis(); |     instance->last_update_timestamp = millis(); | ||||||
| 
 | 
 | ||||||
|  |     instance->history[instance->last_index_write].real_frequency = frequency; | ||||||
|  |     instance->history[instance->last_index_write].preset = preset; | ||||||
|     instance->history[instance->last_index_write].te = 0; |     instance->history[instance->last_index_write].te = 0; | ||||||
|     instance->history[instance->last_index_write].manufacture_name = NULL; |     instance->history[instance->last_index_write].manufacture_name = NULL; | ||||||
|     instance->history[instance->last_index_write].name = protocol->name; |     instance->history[instance->last_index_write].name = protocol->name; | ||||||
| @ -161,4 +167,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { | |||||||
|     instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; |     instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; | ||||||
| 
 | 
 | ||||||
|     instance->last_index_write++; |     instance->last_index_write++; | ||||||
|  |     return true; | ||||||
| } | } | ||||||
| @ -1,3 +1,4 @@ | |||||||
|  | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||||
| @ -94,8 +95,15 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output | |||||||
|  *  |  *  | ||||||
|  * @param instance  - SubGhzHistory instance |  * @param instance  - SubGhzHistory instance | ||||||
|  * @param context    - SubGhzProtocolCommon context |  * @param context    - SubGhzProtocolCommon context | ||||||
|  |  * @param frequency - frequency Hz | ||||||
|  |  * @param preset    - FuriHalSubGhzPreset preset | ||||||
|  |  * @return bool; | ||||||
|  */ |  */ | ||||||
| void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | bool subghz_history_add_to_history( | ||||||
|  |     SubGhzHistory* instance, | ||||||
|  |     void* context, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
| 
 | 
 | ||||||
| /** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
 | /** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
 | ||||||
|  *  |  *  | ||||||
| @ -104,3 +112,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | |||||||
|  * @return SubGhzProtocolCommonLoad* |  * @return SubGhzProtocolCommonLoad* | ||||||
|  */ |  */ | ||||||
| SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | void subghz_hopper_update(void* context); | ||||||
|  | |||||||
| @ -19,6 +19,9 @@ void subghz_begin(FuriHalSubGhzPreset preset) { | |||||||
| 
 | 
 | ||||||
| uint32_t subghz_rx(void* context, uint32_t frequency) { | uint32_t subghz_rx(void* context, uint32_t frequency) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|  |     if(!furi_hal_subghz_is_frequency_valid(frequency)) { | ||||||
|  |         furi_check(0); | ||||||
|  |     } | ||||||
|     SubGhzWorker* worker = context; |     SubGhzWorker* worker = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
| @ -33,6 +36,9 @@ uint32_t subghz_rx(void* context, uint32_t frequency) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t subghz_tx(uint32_t frequency) { | uint32_t subghz_tx(uint32_t frequency) { | ||||||
|  |     if(!furi_hal_subghz_is_frequency_valid(frequency)) { | ||||||
|  |         furi_check(0); | ||||||
|  |     } | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
|     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); |     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
| @ -53,6 +59,7 @@ void subghz_rx_end(void* context) { | |||||||
|         subghz_worker_stop(worker); |         subghz_worker_stop(worker); | ||||||
|         furi_hal_subghz_stop_async_rx(); |         furi_hal_subghz_stop_async_rx(); | ||||||
|     } |     } | ||||||
|  |     furi_hal_subghz_idle(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_sleep(void) { | void subghz_sleep(void) { | ||||||
| @ -66,41 +73,46 @@ void subghz_frequency_preset_to_str(void* context, string_t output) { | |||||||
|         output, |         output, | ||||||
|         "Frequency: %d\n" |         "Frequency: %d\n" | ||||||
|         "Preset: %d\n", |         "Preset: %d\n", | ||||||
|         (int)subghz->frequency, |         (int)subghz->txrx->frequency, | ||||||
|         (int)subghz->preset); |         (int)subghz->txrx->preset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_tx_start(void* context) { | void subghz_tx_start(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz->encoder = subghz_protocol_encoder_common_alloc(); |     subghz->txrx->encoder = subghz_protocol_encoder_common_alloc(); | ||||||
|     subghz->encoder->repeat = 200; //max repeat with the button held down
 |     subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
 | ||||||
|     //get upload
 |     //get upload
 | ||||||
|     if(subghz->protocol_result->get_upload_protocol) { |     if(subghz->txrx->protocol_result->get_upload_protocol) { | ||||||
|         if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) { |         if(subghz->txrx->protocol_result->get_upload_protocol( | ||||||
|             if(subghz->preset) { |                subghz->txrx->protocol_result, subghz->txrx->encoder)) { | ||||||
|                 subghz_begin(subghz->preset); |             if(subghz->txrx->preset) { | ||||||
|  |                 subghz_begin(subghz->txrx->preset); | ||||||
|             } else { |             } else { | ||||||
|                 subghz_begin(FuriHalSubGhzPresetOok650Async); |                 subghz_begin(FuriHalSubGhzPresetOok270Async); | ||||||
|             } |             } | ||||||
|             if(subghz->frequency) { |             if(subghz->txrx->frequency) { | ||||||
|                 subghz_tx(subghz->frequency); |                 subghz_tx(subghz->txrx->frequency); | ||||||
|             } else { |             } else { | ||||||
|                 subghz_tx(433920000); |                 subghz_tx(433920000); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             //Start TX
 |             //Start TX
 | ||||||
|             furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder); |             furi_hal_subghz_start_async_tx( | ||||||
|  |                 subghz_protocol_encoder_common_yield, subghz->txrx->encoder); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_tx_stop(void* context) { | void subghz_tx_stop(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     //Stop TX
 |     //Stop TX
 | ||||||
|     furi_hal_subghz_stop_async_tx(); |     furi_hal_subghz_stop_async_tx(); | ||||||
|     subghz_protocol_encoder_common_free(subghz->encoder); |     subghz_protocol_encoder_common_free(subghz->txrx->encoder); | ||||||
|  |     furi_hal_subghz_idle(); | ||||||
|     //if protocol dynamic then we save the last upload
 |     //if protocol dynamic then we save the last upload
 | ||||||
|     if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { |     if(subghz->txrx->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { | ||||||
|         subghz_save_protocol_to_file(subghz, subghz->text_store); |         subghz_save_protocol_to_file(subghz, subghz->text_store); | ||||||
|     } |     } | ||||||
|     notification_message(subghz->notifications, &sequence_reset_red); |     notification_message(subghz->notifications, &sequence_reset_red); | ||||||
| @ -133,7 +145,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|         if(res != 1) { |         if(res != 1) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         subghz->frequency = (uint32_t)data; |         subghz->txrx->frequency = (uint32_t)data; | ||||||
| 
 | 
 | ||||||
|         // Read and parse preset from 2st line
 |         // Read and parse preset from 2st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
| @ -143,7 +155,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|         if(res != 1) { |         if(res != 1) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         subghz->preset = (FuriHalSubGhzPreset)data; |         subghz->txrx->preset = (FuriHalSubGhzPreset)data; | ||||||
| 
 | 
 | ||||||
|         // Read and parse name protocol from 2st line
 |         // Read and parse name protocol from 2st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
| @ -151,13 +163,13 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|         } |         } | ||||||
|         // strlen("Protocol: ") = 10
 |         // strlen("Protocol: ") = 10
 | ||||||
|         string_right(temp_str, 10); |         string_right(temp_str, 10); | ||||||
|         subghz->protocol_result = |         subghz->txrx->protocol_result = | ||||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); |             subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); | ||||||
|         if(subghz->protocol_result == NULL) { |         if(subghz->txrx->protocol_result == NULL) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz->protocol_result->to_load_protocol_from_file( |         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( | ||||||
|                file_worker, subghz->protocol_result)) { |                file_worker, subghz->txrx->protocol_result)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         loaded = true; |         loaded = true; | ||||||
| @ -175,8 +187,9 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | ||||||
|  |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     furi_assert(subghz->protocol_result); |     furi_assert(subghz->txrx->protocol_result); | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     FileWorker* file_worker = file_worker_alloc(false); | ||||||
|     string_t dev_file_name; |     string_t dev_file_name; | ||||||
|     string_init(dev_file_name); |     string_init(dev_file_name); | ||||||
| @ -210,7 +223,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         //Get string save
 |         //Get string save
 | ||||||
|         subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str); |         subghz->txrx->protocol_result->to_save_string(subghz->txrx->protocol_result, temp_str); | ||||||
|         // Prepare and write data to file
 |         // Prepare and write data to file
 | ||||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { |         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { | ||||||
|             break; |             break; | ||||||
| @ -276,7 +289,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
|         if(sscanf_res != 1) { |         if(sscanf_res != 1) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         subghz->frequency = (uint32_t)data; |         subghz->txrx->frequency = (uint32_t)data; | ||||||
| 
 | 
 | ||||||
|         // Read and parse preset from 2st line
 |         // Read and parse preset from 2st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
| @ -286,7 +299,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
|         if(sscanf_res != 1) { |         if(sscanf_res != 1) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         subghz->preset = (FuriHalSubGhzPreset)data; |         subghz->txrx->preset = (FuriHalSubGhzPreset)data; | ||||||
| 
 | 
 | ||||||
|         // Read and parse name protocol from 3st line
 |         // Read and parse name protocol from 3st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
| @ -294,13 +307,13 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
|         } |         } | ||||||
|         // strlen("Protocol: ") = 10
 |         // strlen("Protocol: ") = 10
 | ||||||
|         string_right(temp_str, 10); |         string_right(temp_str, 10); | ||||||
|         subghz->protocol_result = |         subghz->txrx->protocol_result = | ||||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); |             subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); | ||||||
|         if(subghz->protocol_result == NULL) { |         if(subghz->txrx->protocol_result == NULL) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz->protocol_result->to_load_protocol_from_file( |         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( | ||||||
|                file_worker, subghz->protocol_result)) { |                file_worker, subghz->txrx->protocol_result)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         res = true; |         res = true; | ||||||
| @ -328,3 +341,57 @@ uint32_t subghz_random_serial(void) { | |||||||
|     } |     } | ||||||
|     return (uint32_t)rand(); |     return (uint32_t)rand(); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void subghz_hopper_update(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzTxRx* txrx = context; | ||||||
|  | 
 | ||||||
|  |     switch(txrx->hopper_state) { | ||||||
|  |     case SubGhzHopperStateOFF: | ||||||
|  |         return; | ||||||
|  |         break; | ||||||
|  |     case SubGhzHopperStatePause: | ||||||
|  |         return; | ||||||
|  |         break; | ||||||
|  |     case SubGhzHopperStateRSSITimeOut: | ||||||
|  |         if(txrx->hopper_timeout != 0) { | ||||||
|  |             txrx->hopper_timeout--; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     float rssi = -127.0f; | ||||||
|  |     if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { | ||||||
|  |         // See RSSI Calculation timings in CC1101 17.3 RSSI
 | ||||||
|  |         rssi = furi_hal_subghz_get_rssi(); | ||||||
|  | 
 | ||||||
|  |         // Stay if RSSI is high enough
 | ||||||
|  |         if(rssi > -90.0f) { | ||||||
|  |             txrx->hopper_timeout = 10; | ||||||
|  |             txrx->hopper_state = SubGhzHopperStateRSSITimeOut; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         txrx->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Select next frequency
 | ||||||
|  |     if(txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) { | ||||||
|  |         txrx->hopper_idx_frequency++; | ||||||
|  |     } else { | ||||||
|  |         txrx->hopper_idx_frequency = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|  |         subghz_rx_end(txrx->worker); | ||||||
|  |         txrx->txrx_state = SubGhzTxRxStateIdle; | ||||||
|  |     }; | ||||||
|  |     if(txrx->txrx_state == SubGhzTxRxStateIdle) { | ||||||
|  |         subghz_protocol_reset(txrx->protocol); | ||||||
|  |         txrx->frequency = subghz_hopper_frequencies[txrx->hopper_idx_frequency]; | ||||||
|  |         subghz_rx(txrx->worker, txrx->frequency); | ||||||
|  |         txrx->txrx_state = SubGhzTxRxStateRx; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -15,9 +15,9 @@ | |||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
| #include <gui/modules/dialog_ex.h> |  | ||||||
| #include <gui/modules/popup.h> | #include <gui/modules/popup.h> | ||||||
| #include <gui/modules/text_input.h> | #include <gui/modules/text_input.h> | ||||||
|  | #include <gui/modules/widget.h> | ||||||
| 
 | 
 | ||||||
| #include <subghz/scenes/subghz_scene.h> | #include <subghz/scenes/subghz_scene.h> | ||||||
| 
 | 
 | ||||||
| @ -26,6 +26,8 @@ | |||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||||
| #include "subghz_history.h" | #include "subghz_history.h" | ||||||
| 
 | 
 | ||||||
|  | #include <gui/modules/variable-item-list.h> | ||||||
|  | 
 | ||||||
| #define SUBGHZ_TEXT_STORE_SIZE 128 | #define SUBGHZ_TEXT_STORE_SIZE 128 | ||||||
| 
 | 
 | ||||||
| #define NOTIFICATION_STARTING_STATE 0u | #define NOTIFICATION_STARTING_STATE 0u | ||||||
| @ -33,48 +35,81 @@ | |||||||
| #define NOTIFICATION_TX_STATE 2u | #define NOTIFICATION_TX_STATE 2u | ||||||
| #define NOTIFICATION_RX_STATE 3u | #define NOTIFICATION_RX_STATE 3u | ||||||
| 
 | 
 | ||||||
|  | extern const char* const subghz_frequencies_text[]; | ||||||
| extern const uint32_t subghz_frequencies[]; | extern const uint32_t subghz_frequencies[]; | ||||||
|  | extern const uint32_t subghz_hopper_frequencies[]; | ||||||
| extern const uint32_t subghz_frequencies_count; | extern const uint32_t subghz_frequencies_count; | ||||||
|  | extern const uint32_t subghz_hopper_frequencies_count; | ||||||
| extern const uint32_t subghz_frequencies_433_92; | extern const uint32_t subghz_frequencies_433_92; | ||||||
| 
 | 
 | ||||||
| struct SubGhz { | /** SubGhzTxRx state */ | ||||||
|     Gui* gui; | typedef enum { | ||||||
|     NotificationApp* notifications; |     SubGhzTxRxStateIdle, | ||||||
|  |     SubGhzTxRxStateRx, | ||||||
|  |     SubGhzTxRxStateTx, | ||||||
|  | } SubGhzTxRxState; | ||||||
| 
 | 
 | ||||||
|  | /** SubGhzHopperState state */ | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzHopperStateOFF, | ||||||
|  |     SubGhzHopperStateRunnig, | ||||||
|  |     SubGhzHopperStatePause, | ||||||
|  |     SubGhzHopperStateRSSITimeOut, | ||||||
|  | } SubGhzHopperState; | ||||||
|  | 
 | ||||||
|  | struct SubGhzTxRx { | ||||||
|     SubGhzWorker* worker; |     SubGhzWorker* worker; | ||||||
|     SubGhzProtocol* protocol; |     SubGhzProtocol* protocol; | ||||||
|     SubGhzProtocolCommon* protocol_result; |     SubGhzProtocolCommon* protocol_result; | ||||||
|     SubGhzProtocolCommonEncoder* encoder; |     SubGhzProtocolCommonEncoder* encoder; | ||||||
|     uint32_t frequency; |     uint32_t frequency; | ||||||
|     FuriHalSubGhzPreset preset; |     FuriHalSubGhzPreset preset; | ||||||
|  |     SubGhzHistory* history; | ||||||
|  |     uint16_t idx_menu_chosen; | ||||||
|  |     SubGhzTxRxState txrx_state; | ||||||
|  |     //bool hopper_runing;
 | ||||||
|  |     SubGhzHopperState hopper_state; | ||||||
|  |     uint8_t hopper_timeout; | ||||||
|  |     uint8_t hopper_idx_frequency; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzTxRx SubGhzTxRx; | ||||||
|  | 
 | ||||||
|  | struct SubGhz { | ||||||
|  |     Gui* gui; | ||||||
|  |     NotificationApp* notifications; | ||||||
|  | 
 | ||||||
|  |     SubGhzTxRx* txrx; | ||||||
| 
 | 
 | ||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
| 
 | 
 | ||||||
|     Submenu* submenu; |     Submenu* submenu; | ||||||
|     DialogEx* dialog_ex; |  | ||||||
|     Popup* popup; |     Popup* popup; | ||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
|  |     Widget* widget; | ||||||
|     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; |     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||||
|     uint8_t state_notifications; |     uint8_t state_notifications; | ||||||
| 
 | 
 | ||||||
|     SubghzReceiver* subghz_receiver; |     SubghzReceiver* subghz_receiver; | ||||||
|     SubghzTransmitter* subghz_transmitter; |     SubghzTransmitter* subghz_transmitter; | ||||||
|  |     VariableItemList* variable_item_list; | ||||||
| 
 | 
 | ||||||
|     SubghzTestStatic* subghz_test_static; |     SubghzTestStatic* subghz_test_static; | ||||||
|     SubghzTestCarrier* subghz_test_carrier; |     SubghzTestCarrier* subghz_test_carrier; | ||||||
|     SubghzTestPacket* subghz_test_packet; |     SubghzTestPacket* subghz_test_packet; | ||||||
|  |     string_t error_str; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubGhzViewMenu, |     SubGhzViewMenu, | ||||||
| 
 | 
 | ||||||
|     SubGhzViewDialogEx, |  | ||||||
|     SubGhzViewReceiver, |     SubGhzViewReceiver, | ||||||
|     SubGhzViewPopup, |     SubGhzViewPopup, | ||||||
|     SubGhzViewTextInput, |     SubGhzViewTextInput, | ||||||
|  |     SubGhzViewWidget, | ||||||
|     SubGhzViewTransmitter, |     SubGhzViewTransmitter, | ||||||
| 
 |     SubGhzViewVariableItemList, | ||||||
|     SubGhzViewStatic, |     SubGhzViewStatic, | ||||||
|     SubGhzViewTestCarrier, |     SubGhzViewTestCarrier, | ||||||
|     SubGhzViewTestPacket, |     SubGhzViewTestPacket, | ||||||
| @ -86,8 +121,8 @@ uint32_t subghz_tx(uint32_t frequency); | |||||||
| void subghz_idle(void); | void subghz_idle(void); | ||||||
| void subghz_rx_end(void* context); | void subghz_rx_end(void* context); | ||||||
| void subghz_sleep(void); | void subghz_sleep(void); | ||||||
| void subghz_transmitter_tx_start(void* context); | void subghz_tx_start(void* context); | ||||||
| void subghz_transmitter_tx_stop(void* context); | void subghz_tx_stop(void* context); | ||||||
| bool subghz_key_load(SubGhz* subghz, const char* file_path); | bool subghz_key_load(SubGhz* subghz, const char* file_path); | ||||||
| bool subghz_save_protocol_to_file(void* context, const char* dev_name); | bool subghz_save_protocol_to_file(void* context, const char* dev_name); | ||||||
| bool subghz_load_protocol_from_file(SubGhz* subghz); | bool subghz_load_protocol_from_file(SubGhz* subghz); | ||||||
|  | |||||||
| @ -1,42 +1,32 @@ | |||||||
| #include "subghz_receiver.h" | #include "subghz_receiver.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <furi.h> | 
 | ||||||
| #include <furi-hal.h> |  | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> |  | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> |  | ||||||
| 
 |  | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <m-array.h> | ||||||
| 
 | 
 | ||||||
| #define FRAME_HEIGHT 12 | #define FRAME_HEIGHT 12 | ||||||
| #define MAX_LEN_PX 100 | #define MAX_LEN_PX 100 | ||||||
| #define MENU_ITEMS 4 | #define MENU_ITEMS 4 | ||||||
| 
 | 
 | ||||||
| #define COUNT_FREQUNCY_HOPPER 3 | typedef struct { | ||||||
| const uint32_t subghz_frequencies_hopper[] = { |     string_t item_str; | ||||||
|     /* 300 - 348 */ |     uint8_t type; | ||||||
|     315000000, | } SubGhzReceiverMenuItem; | ||||||
|     /* 387 - 464 */ | 
 | ||||||
|     433920000, /* LPD433 mid */ | ARRAY_DEF(SubGhzReceiverMenuItemArray, SubGhzReceiverMenuItem, M_POD_OPLIST) | ||||||
|     /* 779 - 928 */ | 
 | ||||||
|     868350000, | #define M_OPL_SubGhzReceiverMenuItemArray_t() \ | ||||||
|  |     ARRAY_OPLIST(SubGhzReceiverMenuItemArray, M_POD_OPLIST) | ||||||
|  | 
 | ||||||
|  | struct SubGhzReceiverHistory { | ||||||
|  |     SubGhzReceiverMenuItemArray_t data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; | ||||||
|     ReceiverSceneStart, |  | ||||||
|     ReceiverSceneMain, |  | ||||||
|     ReceiverSceneConfig, |  | ||||||
|     ReceiverSceneInfo, |  | ||||||
| } SubghzReceiverScene; |  | ||||||
| 
 |  | ||||||
| typedef enum { |  | ||||||
|     SubGhzHopperStateOFF, |  | ||||||
|     SubGhzHopperStatePause, |  | ||||||
|     SubGhzHopperStateRunnig, |  | ||||||
|     SubGhzHopperStateRSSITimeOut, |  | ||||||
| } SubGhzHopperState; |  | ||||||
| 
 | 
 | ||||||
| static const Icon* ReceiverItemIcons[] = { | static const Icon* ReceiverItemIcons[] = { | ||||||
|     [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, |     [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, | ||||||
| @ -48,27 +38,16 @@ struct SubghzReceiver { | |||||||
|     View* view; |     View* view; | ||||||
|     SubghzReceiverCallback callback; |     SubghzReceiverCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
|     SubGhzWorker* worker; |  | ||||||
|     SubGhzProtocol* protocol; |  | ||||||
|     osTimerId timer; |  | ||||||
|     SubGhzHopperState hopper_state; |  | ||||||
|     uint8_t hopper_timeout; |  | ||||||
|     uint32_t event_key_sequence; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t text; |     string_t frequency_str; | ||||||
|     uint16_t scene; |     string_t preset_str; | ||||||
|     SubGhzProtocolCommon* protocol_result; |     string_t history_stat_str; | ||||||
|     SubGhzHistory* history; |     SubGhzReceiverHistory* history; | ||||||
|     uint8_t frequency; |  | ||||||
|     uint8_t temp_frequency; |  | ||||||
|     uint32_t real_frequency; |  | ||||||
| 
 |  | ||||||
|     uint16_t idx; |     uint16_t idx; | ||||||
|     uint16_t list_offset; |     uint16_t list_offset; | ||||||
|     uint16_t history_item; |     uint16_t history_item; | ||||||
|     bool menu; |  | ||||||
| } SubghzReceiverModel; | } SubghzReceiverModel; | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_callback( | void subghz_receiver_set_callback( | ||||||
| @ -81,35 +60,6 @@ void subghz_receiver_set_callback( | |||||||
|     subghz_receiver->context = context; |     subghz_receiver->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_protocol( |  | ||||||
|     SubghzReceiver* subghz_receiver, |  | ||||||
|     SubGhzProtocolCommon* protocol_result, |  | ||||||
|     SubGhzProtocol* protocol) { |  | ||||||
|     furi_assert(subghz_receiver); |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             model->protocol_result = protocol_result; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
|     subghz_receiver->protocol = protocol; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) { |  | ||||||
|     furi_assert(subghz_receiver); |  | ||||||
|     SubGhzProtocolCommon* result = NULL; |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             result = model->protocol_result; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) { |  | ||||||
|     furi_assert(subghz_receiver); |  | ||||||
|     subghz_receiver->worker = worker; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
| 
 | 
 | ||||||
| @ -129,6 +79,38 @@ static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void subghz_receiver_add_item_to_menu( | ||||||
|  |     SubghzReceiver* subghz_receiver, | ||||||
|  |     const char* name, | ||||||
|  |     uint8_t type) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             SubGhzReceiverMenuItem* item_menu = | ||||||
|  |                 SubGhzReceiverMenuItemArray_push_raw(model->history->data); | ||||||
|  |             string_init_set_str(item_menu->item_str, name); | ||||||
|  |             item_menu->type = type; | ||||||
|  |             model->history_item++; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     subghz_receiver_update_offset(subghz_receiver); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_add_data_statusbar( | ||||||
|  |     SubghzReceiver* subghz_receiver, | ||||||
|  |     const char* frequency_str, | ||||||
|  |     const char* preset_str, | ||||||
|  |     const char* history_stat_str) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             string_set(model->frequency_str, frequency_str); | ||||||
|  |             string_set(model->preset_str, preset_str); | ||||||
|  |             string_set(model->history_stat_str, history_stat_str); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { | static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); |     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); | ||||||
| @ -144,462 +126,113 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | ||||||
|     bool scrollbar = model->history_item > 4; |  | ||||||
|     string_t str_buff; |  | ||||||
|     char buffer[64]; |  | ||||||
|     uint32_t frequency; |  | ||||||
|     string_init(str_buff); |  | ||||||
| 
 |  | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
| 
 | 
 | ||||||
|     switch(model->scene) { |     elements_button_left(canvas, "Config"); | ||||||
|     case ReceiverSceneMain: |  | ||||||
|         for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) { |  | ||||||
|             size_t idx = CLAMP(i + model->list_offset, model->history_item, 0); |  | ||||||
|             subghz_history_get_text_item_menu(model->history, str_buff, idx); |  | ||||||
|             elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); |  | ||||||
|             if(model->idx == idx) { |  | ||||||
|                 subghz_receiver_draw_frame(canvas, i, scrollbar); |  | ||||||
|             } else { |  | ||||||
|                 canvas_set_color(canvas, ColorBlack); |  | ||||||
|             } |  | ||||||
|             canvas_draw_icon( |  | ||||||
|                 canvas, |  | ||||||
|                 1, |  | ||||||
|                 2 + i * FRAME_HEIGHT, |  | ||||||
|                 ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]); |  | ||||||
|             canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); |  | ||||||
|             string_clean(str_buff); |  | ||||||
|         } |  | ||||||
|         if(scrollbar) { |  | ||||||
|             elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); |  | ||||||
|         } |  | ||||||
|         canvas_set_color(canvas, ColorBlack); |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
| 
 | 
 | ||||||
|         elements_button_left(canvas, "Config"); |     canvas_draw_str(canvas, 44, 62, string_get_cstr(model->frequency_str)); | ||||||
|         canvas_draw_line(canvas, 46, 51, 125, 51); |     canvas_draw_str(canvas, 79, 62, string_get_cstr(model->preset_str)); | ||||||
|         if(subghz_history_get_text_space_left(model->history, str_buff)) { |     canvas_draw_str(canvas, 96, 62, string_get_cstr(model->history_stat_str)); | ||||||
|             canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff)); |     if(model->history_item == 0) { | ||||||
|         } else { |  | ||||||
|             if((model->real_frequency / 1000 % 10) > 4) { |  | ||||||
|                 frequency = model->real_frequency + 10000; |  | ||||||
|             } else { |  | ||||||
|                 frequency = model->real_frequency; |  | ||||||
|             } |  | ||||||
|             snprintf( |  | ||||||
|                 buffer, |  | ||||||
|                 sizeof(buffer), |  | ||||||
|                 "%03ld.%02ld", |  | ||||||
|                 frequency / 1000000 % 1000, |  | ||||||
|                 frequency / 10000 % 100); |  | ||||||
|             canvas_draw_str(canvas, 44, 62, buffer); |  | ||||||
|             canvas_draw_str(canvas, 79, 62, "AM"); |  | ||||||
|             canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case ReceiverSceneStart: |  | ||||||
|         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); |         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); | ||||||
|         canvas_set_font(canvas, FontPrimary); |         canvas_set_font(canvas, FontPrimary); | ||||||
|         canvas_draw_str(canvas, 63, 46, "Scanning..."); |         canvas_draw_str(canvas, 63, 46, "Scanning..."); | ||||||
|         canvas_set_color(canvas, ColorBlack); |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         elements_button_left(canvas, "Config"); |  | ||||||
|         if((model->real_frequency / 1000 % 10) > 4) { |  | ||||||
|             frequency = model->real_frequency + 10000; |  | ||||||
|         } else { |  | ||||||
|             frequency = model->real_frequency; |  | ||||||
|         } |  | ||||||
|         snprintf( |  | ||||||
|             buffer, |  | ||||||
|             sizeof(buffer), |  | ||||||
|             "%03ld.%02ld", |  | ||||||
|             frequency / 1000000 % 1000, |  | ||||||
|             frequency / 10000 % 100); |  | ||||||
|         canvas_draw_str(canvas, 44, 62, buffer); |  | ||||||
|         canvas_draw_str(canvas, 79, 62, "AM"); |  | ||||||
|         subghz_history_get_text_space_left(model->history, str_buff); |  | ||||||
|         canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); |  | ||||||
|         canvas_draw_line(canvas, 46, 51, 125, 51); |         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||||
|         break; |         return; | ||||||
| 
 |  | ||||||
|     case ReceiverSceneConfig: |  | ||||||
|         if(model->frequency < subghz_frequencies_count) { |  | ||||||
|             snprintf( |  | ||||||
|                 buffer, |  | ||||||
|                 sizeof(buffer), |  | ||||||
|                 "Frequency:  < %03ld.%03ldMHz >", |  | ||||||
|                 model->real_frequency / 1000000 % 1000, |  | ||||||
|                 model->real_frequency / 1000 % 1000); |  | ||||||
|             canvas_draw_str(canvas, 0, 8, buffer); |  | ||||||
|             canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>"); |  | ||||||
|         } else { |  | ||||||
|             canvas_draw_str(canvas, 0, 8, "Frequency: < --- >"); |  | ||||||
|             canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <ON>"); |  | ||||||
|         } |  | ||||||
|         canvas_draw_str(canvas, 0, 28, "Modulation: <AM>"); |  | ||||||
| 
 |  | ||||||
|         elements_button_center(canvas, "Save"); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case ReceiverSceneInfo: |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); |  | ||||||
|         snprintf( |  | ||||||
|             buffer, |  | ||||||
|             sizeof(buffer), |  | ||||||
|             "%03ld.%03ld", |  | ||||||
|             subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000, |  | ||||||
|             subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000); |  | ||||||
|         canvas_draw_str(canvas, 90, 8, buffer); |  | ||||||
|         if(model->protocol_result && model->protocol_result->to_save_string && |  | ||||||
|            strcmp(model->protocol_result->name, "KeeLoq")) { |  | ||||||
|             elements_button_right(canvas, "Save"); |  | ||||||
|             elements_button_center(canvas, "Send"); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
| 
 |  | ||||||
|         break; |  | ||||||
|     } |     } | ||||||
|  |     canvas_draw_line(canvas, 46, 51, 125, 51); | ||||||
| 
 | 
 | ||||||
|  |     bool scrollbar = model->history_item > 4; | ||||||
|  |     string_t str_buff; | ||||||
|  |     string_init(str_buff); | ||||||
|  | 
 | ||||||
|  |     SubGhzReceiverMenuItem* item_menu; | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) { | ||||||
|  |         size_t idx = CLAMP(i + model->list_offset, model->history_item, 0); | ||||||
|  |         item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx); | ||||||
|  |         string_set(str_buff, item_menu->item_str); | ||||||
|  |         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); | ||||||
|  |         if(model->idx == idx) { | ||||||
|  |             subghz_receiver_draw_frame(canvas, i, scrollbar); | ||||||
|  |         } else { | ||||||
|  |             canvas_set_color(canvas, ColorBlack); | ||||||
|  |         } | ||||||
|  |         canvas_draw_icon(canvas, 1, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); | ||||||
|  |         canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); | ||||||
|  |         string_clean(str_buff); | ||||||
|  |     } | ||||||
|  |     if(scrollbar) { | ||||||
|  |         elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); | ||||||
|  |     } | ||||||
|     string_clear(str_buff); |     string_clear(str_buff); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_history_full(void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzReceiver* subghz_receiver = context; |  | ||||||
|     subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context); |  | ||||||
|     subghz_receiver->hopper_state = SubGhzHopperStateOFF; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool subghz_receiver_input(InputEvent* event, void* context) { | bool subghz_receiver_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| 
 |  | ||||||
|     uint8_t scene = 0; |  | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubghzReceiver* subghz_receiver = context; | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             scene = model->scene; |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|     bool can_be_saved = false; |     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
| 
 |         subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); | ||||||
|     switch(scene) { |     } else if( | ||||||
|     case ReceiverSceneMain: |         event->key == InputKeyUp && | ||||||
|         if(event->key == InputKeyBack && event->type == InputTypeShort) { |         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     model->idx = 0; |  | ||||||
|                     model->list_offset = 0; |  | ||||||
|                     model->history_item = 0; |  | ||||||
|                     subghz_history_clean(model->history); |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             return false; |  | ||||||
|         } else if( |  | ||||||
|             event->key == InputKeyUp && |  | ||||||
|             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     if(model->idx != 0) model->idx--; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if( |  | ||||||
|             event->key == InputKeyDown && |  | ||||||
|             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { |  | ||||||
|             subghz_receiver->hopper_state = SubGhzHopperStatePause; |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     model->scene = ReceiverSceneConfig; |  | ||||||
|                     model->temp_frequency = model->frequency; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); |  | ||||||
|         } else if(event->key == InputKeyOk && event->type == InputTypeShort) { |  | ||||||
|             subghz_receiver->event_key_sequence = event->sequence; |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     string_clean(model->text); |  | ||||||
|                     model->protocol_result = subghz_protocol_get_by_name( |  | ||||||
|                         subghz_receiver->protocol, |  | ||||||
|                         subghz_history_get_name(model->history, model->idx)); |  | ||||||
|                     if(model->protocol_result->to_load_protocol != NULL) { |  | ||||||
|                         model->protocol_result->to_load_protocol( |  | ||||||
|                             model->protocol_result, |  | ||||||
|                             subghz_history_get_raw_data(model->history, model->idx)); |  | ||||||
|                         model->protocol_result->to_string(model->protocol_result, model->text); |  | ||||||
|                         model->scene = ReceiverSceneInfo; |  | ||||||
|                     } |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case ReceiverSceneInfo: |  | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { |             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                 can_be_saved = |                 if(model->idx != 0) model->idx--; | ||||||
|                     (model->protocol_result && model->protocol_result->to_save_string && |                 return true; | ||||||
|                      strcmp(model->protocol_result->name, "KeeLoq")); |  | ||||||
|                 return false; |  | ||||||
|             }); |             }); | ||||||
|         if(event->key == InputKeyBack && event->type == InputTypeShort) { |     } else if( | ||||||
|             with_view_model( |         event->key == InputKeyDown && | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|                     subghz_rx_end(subghz_receiver->worker); |  | ||||||
|                     model->real_frequency = |  | ||||||
|                         subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); |  | ||||||
|                     subghz_receiver->hopper_state = SubGhzHopperStateRunnig; |  | ||||||
|                     model->scene = ReceiverSceneMain; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); |  | ||||||
|         } else if(can_be_saved && event->key == InputKeyRight) { |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); |  | ||||||
|             return false; |  | ||||||
|         } else if( |  | ||||||
|             can_be_saved && event->key == InputKeyOk && event->type == InputTypePress && |  | ||||||
|             subghz_receiver->event_key_sequence != event->sequence) { |  | ||||||
|             subghz_receiver->hopper_state = SubGhzHopperStatePause; |  | ||||||
|             subghz_rx_end(subghz_receiver->worker); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context); |  | ||||||
|             return true; |  | ||||||
|         } else if( |  | ||||||
|             can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease && |  | ||||||
|             subghz_receiver->event_key_sequence != event->sequence) { |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case ReceiverSceneConfig: |  | ||||||
|         if(event->type != InputTypeShort) return false; |  | ||||||
|         if(event->key == InputKeyBack) { |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     model->frequency = model->temp_frequency; |  | ||||||
|                     model->real_frequency = subghz_frequencies[model->frequency]; |  | ||||||
|                     subghz_receiver->hopper_state = SubGhzHopperStateRunnig; |  | ||||||
|                     if(subghz_history_get_item(model->history) == 0) { |  | ||||||
|                         model->scene = ReceiverSceneStart; |  | ||||||
|                     } else { |  | ||||||
|                         model->scene = ReceiverSceneMain; |  | ||||||
|                     } |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); |  | ||||||
|         } else if(event->key == InputKeyOk) { |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     if(model->frequency < subghz_frequencies_count) { |  | ||||||
|                         subghz_rx_end(subghz_receiver->worker); |  | ||||||
|                         model->real_frequency = subghz_rx( |  | ||||||
|                             subghz_receiver->worker, subghz_frequencies[model->frequency]); |  | ||||||
|                         subghz_receiver->hopper_state = SubGhzHopperStateOFF; |  | ||||||
|                     } else { |  | ||||||
|                         osTimerStart(subghz_receiver->timer, 1024 / 10); |  | ||||||
|                         subghz_receiver->hopper_state = SubGhzHopperStateRunnig; |  | ||||||
|                     } |  | ||||||
|                     if(subghz_history_get_item(model->history) == 0) { |  | ||||||
|                         model->scene = ReceiverSceneStart; |  | ||||||
|                     } else { |  | ||||||
|                         model->scene = ReceiverSceneMain; |  | ||||||
|                     } |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); |  | ||||||
|         } else { |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     bool model_updated = false; |  | ||||||
| 
 |  | ||||||
|                     if(event->key == InputKeyLeft) { |  | ||||||
|                         if(model->frequency > 0) model->frequency--; |  | ||||||
|                         model_updated = true; |  | ||||||
|                     } else if(event->key == InputKeyRight) { |  | ||||||
|                         if(model->frequency < subghz_frequencies_count) model->frequency++; |  | ||||||
|                         model_updated = true; |  | ||||||
|                     } |  | ||||||
|                     if(model_updated) { |  | ||||||
|                         model->real_frequency = subghz_frequencies[model->frequency]; |  | ||||||
|                     } |  | ||||||
|                     return model_updated; |  | ||||||
|                 }); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     case ReceiverSceneStart: |  | ||||||
|         if(event->type != InputTypeShort) return false; |  | ||||||
|         if(event->key == InputKeyBack) { |  | ||||||
|             return false; |  | ||||||
|         } else if(event->key == InputKeyLeft) { |  | ||||||
|             subghz_receiver->hopper_state = SubGhzHopperStatePause; |  | ||||||
|             with_view_model( |  | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|                     model->temp_frequency = model->frequency; |  | ||||||
|                     model->scene = ReceiverSceneConfig; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |  | ||||||
|     if(scene != ReceiverSceneInfo) { |  | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { |             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                 if(subghz_history_get_text_space_left(model->history, NULL)) { |                 if(model->idx != model->history_item - 1) model->idx++; | ||||||
|                     subghz_receiver_history_full(subghz_receiver); |                 return true; | ||||||
|  |             }); | ||||||
|  |     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|  |         subghz_receiver->callback(SubghzReceverEventConfig, 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); | ||||||
|                 } |                 } | ||||||
|                 return false; |                 return false; | ||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     subghz_receiver_update_offset(subghz_receiver); | ||||||
|  | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_text_callback(string_t text, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzReceiver* subghz_receiver = context; |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             string_set(model->text, text); |  | ||||||
|             model->scene = ReceiverSceneMain; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzReceiver* subghz_receiver = context; |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             model->protocol_result = parser; |  | ||||||
|             subghz_history_set_frequency_preset( |  | ||||||
|                 model->history, |  | ||||||
|                 model->history_item, |  | ||||||
|                 model->real_frequency, |  | ||||||
|                 FuriHalSubGhzPresetOok650Async); |  | ||||||
|             subghz_history_add_to_history(model->history, parser); |  | ||||||
| 
 |  | ||||||
|             model->history_item = subghz_history_get_item(model->history); |  | ||||||
|             model->scene = ReceiverSceneMain; |  | ||||||
|             if(subghz_history_get_text_space_left(model->history, NULL)) { |  | ||||||
|                 subghz_receiver_history_full(subghz_receiver); |  | ||||||
|             } |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
|     subghz_protocol_reset(subghz_receiver->protocol); |  | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void subghz_receiver_timer_callback(void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzReceiver* subghz_receiver = context; |  | ||||||
| 
 |  | ||||||
|     switch(subghz_receiver->hopper_state) { |  | ||||||
|     case SubGhzHopperStatePause: |  | ||||||
|         return; |  | ||||||
|         break; |  | ||||||
|     case SubGhzHopperStateOFF: |  | ||||||
|         osTimerStop(subghz_receiver->timer); |  | ||||||
|         return; |  | ||||||
|         break; |  | ||||||
|     case SubGhzHopperStateRSSITimeOut: |  | ||||||
|         if(subghz_receiver->hopper_timeout != 0) { |  | ||||||
|             subghz_receiver->hopper_timeout--; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     float rssi = -127.0f; |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) { |  | ||||||
|                 // See RSSI Calculation timings in CC1101 17.3 RSSI
 |  | ||||||
|                 rssi = furi_hal_subghz_get_rssi(); |  | ||||||
| 
 |  | ||||||
|                 // Stay if RSSI is high enough
 |  | ||||||
|                 if(rssi > -90.0f) { |  | ||||||
|                     subghz_receiver->hopper_timeout = 10; |  | ||||||
|                     subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut; |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 subghz_receiver->hopper_state = SubGhzHopperStateRunnig; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Select next frequency
 |  | ||||||
|             if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) { |  | ||||||
|                 model->frequency++; |  | ||||||
|             } else { |  | ||||||
|                 model->frequency = 0; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Restart radio
 |  | ||||||
|             furi_hal_subghz_idle(); |  | ||||||
|             subghz_protocol_reset(subghz_receiver->protocol); |  | ||||||
|             model->real_frequency = furi_hal_subghz_set_frequency_and_path( |  | ||||||
|                 subghz_frequencies_hopper[model->frequency]); |  | ||||||
|             furi_hal_subghz_rx(); |  | ||||||
| 
 |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_enter(void* context) { | void subghz_receiver_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     //SubghzReceiver* subghz_receiver = context;
 | ||||||
|     //Start CC1101 Rx
 |  | ||||||
|     subghz_begin(FuriHalSubGhzPresetOok650Async); |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             subghz_rx_end(subghz_receiver->worker); |  | ||||||
|             model->frequency = subghz_frequencies_433_92; |  | ||||||
|             model->real_frequency = |  | ||||||
|                 subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); |  | ||||||
|             if(subghz_history_get_item(model->history) == 0) { |  | ||||||
|                 model->scene = ReceiverSceneStart; |  | ||||||
|             } else { |  | ||||||
|                 model->scene = ReceiverSceneMain; |  | ||||||
|             } |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
|     subghz_protocol_enable_dump( |  | ||||||
|         subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_exit(void* context) { | void subghz_receiver_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubghzReceiver* subghz_receiver = context; | ||||||
|     osTimerStop(subghz_receiver->timer); |  | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_clean(model->text); |             string_clean(model->frequency_str); | ||||||
|             return true; |             string_clean(model->preset_str); | ||||||
|  |             string_clean(model->history_stat_str); | ||||||
|  |                 for | ||||||
|  |                     M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { | ||||||
|  |                         string_clear(item_menu->item_str); | ||||||
|  |                         item_menu->type = 0; | ||||||
|  |                     } | ||||||
|  |                 SubGhzReceiverMenuItemArray_clean(model->history->data); | ||||||
|  |                 model->idx = 0; | ||||||
|  |                 model->list_offset = 0; | ||||||
|  |                 model->history_item = 0; | ||||||
|  |                 return false; | ||||||
|         }); |         }); | ||||||
|     // Stop CC1101 Rx
 |  | ||||||
|     subghz_rx_end(subghz_receiver->worker); |  | ||||||
|     subghz_sleep(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzReceiver* subghz_receiver_alloc() { | SubghzReceiver* subghz_receiver_alloc() { | ||||||
| @ -616,14 +249,14 @@ SubghzReceiver* subghz_receiver_alloc() { | |||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_init(model->text); |             string_init(model->frequency_str); | ||||||
|             model->history = subghz_history_alloc(); |             string_init(model->preset_str); | ||||||
|  |             string_init(model->history_stat_str); | ||||||
|  |             model->history = furi_alloc(sizeof(SubGhzReceiverHistory)); | ||||||
|  |             SubGhzReceiverMenuItemArray_init(model->history->data); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     subghz_receiver->timer = |  | ||||||
|         osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL); |  | ||||||
|     subghz_receiver->hopper_state = SubGhzHopperStateOFF; |  | ||||||
|     return subghz_receiver; |     return subghz_receiver; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -632,11 +265,18 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) { | |||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_clear(model->text); |             string_clear(model->frequency_str); | ||||||
|             subghz_history_free(model->history); |             string_clear(model->preset_str); | ||||||
|             return false; |             string_clear(model->history_stat_str); | ||||||
|  |                 for | ||||||
|  |                     M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { | ||||||
|  |                         string_clear(item_menu->item_str); | ||||||
|  |                         item_menu->type = 0; | ||||||
|  |                     } | ||||||
|  |                 SubGhzReceiverMenuItemArray_clear(model->history->data); | ||||||
|  |                 free(model->history); | ||||||
|  |                 return false; | ||||||
|         }); |         }); | ||||||
|     osTimerDelete(subghz_receiver->timer); |  | ||||||
|     view_free(subghz_receiver->view); |     view_free(subghz_receiver->view); | ||||||
|     free(subghz_receiver); |     free(subghz_receiver); | ||||||
| } | } | ||||||
| @ -646,43 +286,24 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { | |||||||
|     return subghz_receiver->view; |     return subghz_receiver->view; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) { | uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     uint32_t frequency; |     uint32_t idx = 0; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             frequency = subghz_history_get_frequency(model->history, model->idx); |             idx = model->idx; | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
|     return frequency; |     return idx; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) { | void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     FuriHalSubGhzPreset preset; |  | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             preset = subghz_history_get_preset(model->history, model->idx); |             model->idx = idx; | ||||||
|             return false; |             if(model->idx > 2) model->list_offset = idx - 2; | ||||||
|  |             return true; | ||||||
|         }); |         }); | ||||||
|     return preset; |     subghz_receiver_update_offset(subghz_receiver); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) { |  | ||||||
|     furi_assert(subghz_receiver); |  | ||||||
|     uint32_t frequency; |  | ||||||
|     uint32_t preset; |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |  | ||||||
|             frequency = subghz_history_get_frequency(model->history, model->idx); |  | ||||||
|             preset = (uint32_t)subghz_history_get_preset(model->history, model->idx); |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     string_cat_printf( |  | ||||||
|         output, |  | ||||||
|         "Frequency: %d\n" |  | ||||||
|         "Preset: %d\n", |  | ||||||
|         (int)frequency, |  | ||||||
|         (int)preset); |  | ||||||
| } |  | ||||||
| @ -1,21 +1,11 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> |  | ||||||
| #include <lib/subghz/protocols/subghz_protocol.h> |  | ||||||
| #include <lib/subghz/subghz_worker.h> |  | ||||||
| #include "../subghz_history.h" |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzReceverEventOK, |     SubghzReceverEventOK, | ||||||
|     SubghzReceverEventConfig, |     SubghzReceverEventConfig, | ||||||
|     SubghzReceverEventMain, |  | ||||||
|     SubghzReceverEventSave, |  | ||||||
|     SubghzReceverEventBack, |     SubghzReceverEventBack, | ||||||
|     SubghzReceverEventMore, |  | ||||||
|     SubghzReceverEventSendStart, |  | ||||||
|     SubghzReceverEventSendStop, |  | ||||||
|     SubghzReceverEventSendHistoryFull, |  | ||||||
| } SubghzReceverEvent; | } SubghzReceverEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzReceiver SubghzReceiver; | typedef struct SubghzReceiver SubghzReceiver; | ||||||
| @ -33,17 +23,19 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver); | |||||||
| 
 | 
 | ||||||
| View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); | View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_protocol( | void subghz_receiver_add_data_statusbar( | ||||||
|     SubghzReceiver* subghz_receiver, |     SubghzReceiver* subghz_receiver, | ||||||
|     SubGhzProtocolCommon* protocol_result, |     const char* frequency_str, | ||||||
|     SubGhzProtocol* protocol); |     const char* preset_str, | ||||||
|  |     const char* history_stat_str); | ||||||
| 
 | 
 | ||||||
| SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver); | void subghz_receiver_add_item_to_menu( | ||||||
|  |     SubghzReceiver* subghz_receiver, | ||||||
|  |     const char* name, | ||||||
|  |     uint8_t type); | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker); | uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver); | ||||||
| 
 | 
 | ||||||
| uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver); | void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx); | ||||||
| 
 | 
 | ||||||
| FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver); | void subghz_receiver_exit(void* context); | ||||||
| 
 |  | ||||||
| void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output); |  | ||||||
| @ -1,13 +1,8 @@ | |||||||
| #include "subghz_transmitter.h" | #include "subghz_transmitter.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 | 
 | ||||||
| #include <math.h> |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi-hal.h> |  | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> |  | ||||||
| #include <lib/subghz/protocols/subghz_protocol_keeloq.h> |  | ||||||
| 
 | 
 | ||||||
| struct SubghzTransmitter { | struct SubghzTransmitter { | ||||||
|     View* view; |     View* view; | ||||||
| @ -16,11 +11,10 @@ struct SubghzTransmitter { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t text; |     string_t frequency_str; | ||||||
|     uint16_t scene; |     string_t preset_str; | ||||||
|     uint32_t real_frequency; |     string_t key_str; | ||||||
|     FuriHalSubGhzPreset preset; |     uint8_t show_button; | ||||||
|     SubGhzProtocolCommon* protocol; |  | ||||||
| } SubghzTransmitterModel; | } SubghzTransmitterModel; | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_set_callback( | void subghz_transmitter_set_callback( | ||||||
| @ -33,24 +27,19 @@ void subghz_transmitter_set_callback( | |||||||
|     subghz_transmitter->context = context; |     subghz_transmitter->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_set_protocol( | void subghz_transmitter_add_data_to_show( | ||||||
|     SubghzTransmitter* subghz_transmitter, |     SubghzTransmitter* subghz_transmitter, | ||||||
|     SubGhzProtocolCommon* protocol) { |     const char* key_str, | ||||||
|  |     const char* frequency_str, | ||||||
|  |     const char* preset_str, | ||||||
|  |     uint8_t show_button) { | ||||||
|  |     furi_assert(subghz_transmitter); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             model->protocol = protocol; |             string_set(model->key_str, key_str); | ||||||
|             return true; |             string_set(model->frequency_str, frequency_str); | ||||||
|         }); |             string_set(model->preset_str, preset_str); | ||||||
| } |             model->show_button = show_button; | ||||||
| 
 |  | ||||||
| void subghz_transmitter_set_frequency_preset( |  | ||||||
|     SubghzTransmitter* subghz_transmitter, |  | ||||||
|     uint32_t frequency, |  | ||||||
|     FuriHalSubGhzPreset preset) { |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |  | ||||||
|             model->real_frequency = frequency; |  | ||||||
|             model->preset = preset; |  | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| @ -87,26 +76,13 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | ||||||
|     char buffer[64]; |  | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); |     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str)); | ||||||
|     snprintf( |     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str)); | ||||||
|         buffer, |     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str)); | ||||||
|         sizeof(buffer), |     if(model->show_button) subghz_transmitter_button_right(canvas, "Send"); | ||||||
|         "%03ld.%03ld", |  | ||||||
|         model->real_frequency / 1000000 % 1000, |  | ||||||
|         model->real_frequency / 1000 % 1000); |  | ||||||
|     canvas_draw_str(canvas, 90, 8, buffer); |  | ||||||
| 
 |  | ||||||
|     if(model->protocol && model->protocol->get_upload_protocol) { |  | ||||||
|         if((!strcmp(model->protocol->name, "KeeLoq")) && |  | ||||||
|            (!strcmp(subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         subghz_transmitter_button_right(canvas, "Send"); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_transmitter_input(InputEvent* event, void* context) { | bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||||
| @ -114,26 +90,25 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | |||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubghzTransmitter* subghz_transmitter = context; | ||||||
|     bool can_be_sent = false; |     bool can_be_sent = false; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|  |         with_view_model( | ||||||
|  |             subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|  |                 string_clean(model->frequency_str); | ||||||
|  |                 string_clean(model->preset_str); | ||||||
|  |                 string_clean(model->key_str); | ||||||
|  |                 model->show_button = 0; | ||||||
|  |                 return false; | ||||||
|  |             }); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             if(model->protocol && model->protocol->get_upload_protocol) { |             if(model->show_button) { | ||||||
|                 if((!strcmp(model->protocol->name, "KeeLoq")) && |  | ||||||
|                    (!strcmp( |  | ||||||
|                        subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { |  | ||||||
|                     return false; |  | ||||||
|                 } |  | ||||||
|                 can_be_sent = true; |                 can_be_sent = true; | ||||||
|             } |             } | ||||||
|             //can_be_sent = (model->protocol && model->protocol->get_upload_protocol);
 |  | ||||||
|             string_clean(model->text); |  | ||||||
|             model->protocol->to_string(model->protocol, model->text); |  | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     //if(event->type != InputTypeShort) return false;
 |  | ||||||
| 
 | 
 | ||||||
|     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { |     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { | ||||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); |         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); | ||||||
| @ -146,37 +121,14 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_text_callback(string_t text, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |  | ||||||
|             string_set(model->text, text); |  | ||||||
|             model->scene = 0; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_transmitter_enter(void* context) { | void subghz_transmitter_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |     // SubghzTransmitter* subghz_transmitter = context;
 | ||||||
|     with_view_model( |  | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |  | ||||||
|             string_clean(model->text); |  | ||||||
|             model->protocol->to_string(model->protocol, model->text); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_exit(void* context) { | void subghz_transmitter_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |     // SubghzTransmitter* subghz_transmitter = context;
 | ||||||
|     with_view_model( |  | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |  | ||||||
|             string_clean(model->text); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzTransmitter* subghz_transmitter_alloc() { | SubghzTransmitter* subghz_transmitter_alloc() { | ||||||
| @ -194,7 +146,9 @@ SubghzTransmitter* subghz_transmitter_alloc() { | |||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             string_init(model->text); |             string_init(model->frequency_str); | ||||||
|  |             string_init(model->preset_str); | ||||||
|  |             string_init(model->key_str); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     return subghz_transmitter; |     return subghz_transmitter; | ||||||
| @ -205,7 +159,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { | |||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             string_clear(model->text); |             string_clear(model->frequency_str); | ||||||
|  |             string_clear(model->preset_str); | ||||||
|  |             string_clear(model->key_str); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     view_free(subghz_transmitter->view); |     view_free(subghz_transmitter->view); | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTransmitterEventSendStart, |     SubghzTransmitterEventSendStart, | ||||||
| @ -25,10 +24,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter); | |||||||
| 
 | 
 | ||||||
| View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); | View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_set_protocol( | void subghz_transmitter_add_data_to_show( | ||||||
|     SubghzTransmitter* subghz_transmitter, |     SubghzTransmitter* subghz_transmitter, | ||||||
|     SubGhzProtocolCommon* protocol); |     const char* key_str, | ||||||
| void subghz_transmitter_set_frequency_preset( |     const char* frequency_str, | ||||||
|     SubghzTransmitter* subghz_transmitter, |     const char* preset_str, | ||||||
|     uint32_t frequency, |     uint8_t show_button); | ||||||
|     FuriHalSubGhzPreset preset); |  | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
| #include "subghz_protocol_faac_slh.h" | #include "subghz_protocol_faac_slh.h" | ||||||
| #include "subghz_protocol_nero_sketch.h" | #include "subghz_protocol_nero_sketch.h" | ||||||
| #include "subghz_protocol_star_line.h" | #include "subghz_protocol_star_line.h" | ||||||
|  | #include "subghz_protocol_nero_radio.h" | ||||||
| 
 | 
 | ||||||
| #include "../subghz_keystore.h" | #include "../subghz_keystore.h" | ||||||
| 
 | 
 | ||||||
| @ -27,6 +28,7 @@ typedef enum { | |||||||
|     SubGhzProtocolTypeFaacSLH, |     SubGhzProtocolTypeFaacSLH, | ||||||
|     SubGhzProtocolTypeNeroSketch, |     SubGhzProtocolTypeNeroSketch, | ||||||
|     SubGhzProtocolTypeStarLine, |     SubGhzProtocolTypeStarLine, | ||||||
|  |     SubGhzProtocolTypeNeroRadio, | ||||||
| 
 | 
 | ||||||
|     SubGhzProtocolTypeMax, |     SubGhzProtocolTypeMax, | ||||||
| } SubGhzProtocolType; | } SubGhzProtocolType; | ||||||
| @ -88,6 +90,8 @@ SubGhzProtocol* subghz_protocol_alloc() { | |||||||
|         (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc(); |         (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc(); | ||||||
|     instance->protocols[SubGhzProtocolTypeStarLine] = |     instance->protocols[SubGhzProtocolTypeStarLine] = | ||||||
|         (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore); |         (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore); | ||||||
|  |     instance->protocols[SubGhzProtocolTypeNeroRadio] = | ||||||
|  |         (SubGhzProtocolCommon*)subghz_protocol_nero_radio_alloc(); | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| @ -113,6 +117,8 @@ void subghz_protocol_free(SubGhzProtocol* instance) { | |||||||
|         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); |         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); | ||||||
|     subghz_protocol_star_line_free( |     subghz_protocol_star_line_free( | ||||||
|         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); |         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); | ||||||
|  |     subghz_protocol_nero_radio_free( | ||||||
|  |         (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); | ||||||
| 
 | 
 | ||||||
|     subghz_keystore_free(instance->keystore); |     subghz_keystore_free(instance->keystore); | ||||||
| 
 | 
 | ||||||
| @ -163,7 +169,6 @@ void subghz_protocol_enable_dump( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { | void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { | ||||||
|     // subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name);
 |  | ||||||
|     subghz_protocol_nice_flor_s_name_file( |     subghz_protocol_nice_flor_s_name_file( | ||||||
|         (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); |         (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); | ||||||
| } | } | ||||||
| @ -191,6 +196,8 @@ void subghz_protocol_reset(SubGhzProtocol* instance) { | |||||||
|         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); |         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); | ||||||
|     subghz_protocol_star_line_reset( |     subghz_protocol_star_line_reset( | ||||||
|         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); |         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); | ||||||
|  |     subghz_protocol_nero_radio_reset( | ||||||
|  |         (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { | void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { | ||||||
| @ -220,4 +227,8 @@ void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t durati | |||||||
|         duration); |         duration); | ||||||
|     subghz_protocol_star_line_parse( |     subghz_protocol_star_line_parse( | ||||||
|         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration); |         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration); | ||||||
|  |     subghz_protocol_nero_radio_parse( | ||||||
|  |         (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio], | ||||||
|  |         level, | ||||||
|  |         duration); | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance); | |||||||
| 
 | 
 | ||||||
| /** Get upload protocol
 | /** Get upload protocol
 | ||||||
|  *  |  *  | ||||||
|  * @param instance - SubGhzProtocolCame instance |  * @param instance - SubGhzProtocolGateTX instance | ||||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  * @return bool |  * @return bool | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -398,9 +398,9 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp | |||||||
|     string_cat_printf( |     string_cat_printf( | ||||||
|         output, |         output, | ||||||
|         "%s %dbit\r\n" |         "%s %dbit\r\n" | ||||||
|         "Key:0x%lX%lX\r\n" |         "Key:%08lX%08lX\r\n" | ||||||
|         "Fix:0x%08lX     Cnt:%04X\r\n" |         "Fix:0x%08lX    Cnt:%04X\r\n" | ||||||
|         "Hop:0x%08lX     Btn:%02lX\r\n" |         "Hop:0x%08lX    Btn:%02lX\r\n" | ||||||
|         "MF:%s\r\n" |         "MF:%s\r\n" | ||||||
|         "Sn:0x%07lX \r\n", |         "Sn:0x%07lX \r\n", | ||||||
|         instance->common.name, |         instance->common.name, | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context); | |||||||
| 
 | 
 | ||||||
| /** Get upload protocol
 | /** Get upload protocol
 | ||||||
|  *  |  *  | ||||||
|  * @param instance - SubGhzProtocolCame instance |  * @param instance - SubGhzProtocolKeeloq instance | ||||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  * @return bool |  * @return bool | ||||||
|  */ |  */ | ||||||
|  | |||||||
							
								
								
									
										280
									
								
								lib/subghz/protocols/subghz_protocol_nero_radio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								lib/subghz/protocols/subghz_protocol_nero_radio.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,280 @@ | |||||||
|  | #include "subghz_protocol_nero_radio.h" | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolNeroRadio { | ||||||
|  |     SubGhzProtocolCommon common; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) { | ||||||
|  |     SubGhzProtocolNeroRadio* instance = furi_alloc(sizeof(SubGhzProtocolNeroRadio)); | ||||||
|  | 
 | ||||||
|  |     instance->common.name = "Nero Radio"; | ||||||
|  |     instance->common.code_min_count_bit_for_found = 55; | ||||||
|  |     instance->common.te_short = 200; | ||||||
|  |     instance->common.te_long = 400; | ||||||
|  |     instance->common.te_delta = 80; | ||||||
|  |     instance->common.type_protocol = TYPE_PROTOCOL_STATIC; | ||||||
|  |     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str; | ||||||
|  |     instance->common.to_save_string = | ||||||
|  |         (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_radio_to_save_str; | ||||||
|  |     instance->common.to_load_protocol_from_file = | ||||||
|  |         (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_radio_to_load_protocol_from_file; | ||||||
|  |     instance->common.to_load_protocol = | ||||||
|  |         (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_radio_to_load_protocol; | ||||||
|  |     instance->common.get_upload_protocol = | ||||||
|  |         (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_radio_send_key; | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_nero_radio_send_key( | ||||||
|  |     SubGhzProtocolNeroRadio* instance, | ||||||
|  |     SubGhzProtocolCommonEncoder* encoder) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     furi_assert(encoder); | ||||||
|  |     size_t index = 0; | ||||||
|  |     encoder->size_upload = 2 + 47 * 2 + 2 + (instance->common.code_last_count_bit * 2); | ||||||
|  |     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; | ||||||
|  | 
 | ||||||
|  |     //Send header
 | ||||||
|  |     encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); | ||||||
|  |     encoder->upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)instance->common.te_short * 37); | ||||||
|  |     for(uint8_t i = 0; i < 47; i++) { | ||||||
|  |         encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); | ||||||
|  |         encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send start bit
 | ||||||
|  |     encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4); | ||||||
|  |     encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); | ||||||
|  | 
 | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->common.code_last_found, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             encoder->upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)instance->common.te_long); | ||||||
|  |             encoder->upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)instance->common.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             encoder->upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)instance->common.te_short); | ||||||
|  |             encoder->upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)instance->common.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) { | ||||||
|  |     instance->common.parser_step = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolNeroRadio instance | ||||||
|  |  */ | ||||||
|  | // void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance) {
 | ||||||
|  | //     //пока не понятно с серийником, но код статический
 | ||||||
|  | //     // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit);
 | ||||||
|  | //     // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
 | ||||||
|  | //     // //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF;
 | ||||||
|  | 
 | ||||||
|  | //     // instance->common.serial = code_fix & 0xFFFFFFF;
 | ||||||
|  | //     // instance->common.btn = (code_fix >> 28) & 0x0F;
 | ||||||
|  | 
 | ||||||
|  | //     //if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
 | ||||||
|  | 
 | ||||||
|  | // }
 | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_nero_radio_parse( | ||||||
|  |     SubGhzProtocolNeroRadio* instance, | ||||||
|  |     bool level, | ||||||
|  |     uint32_t duration) { | ||||||
|  |     switch(instance->common.parser_step) { | ||||||
|  |     case 0: | ||||||
|  |         if((level) && | ||||||
|  |            (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { | ||||||
|  |             instance->common.parser_step = 1; | ||||||
|  |             instance->common.te_last = duration; | ||||||
|  |             instance->common.header_count = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->common.parser_step = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case 1: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) || | ||||||
|  |                (DURATION_DIFF(duration, instance->common.te_short * 4) < | ||||||
|  |                 instance->common.te_delta)) { | ||||||
|  |                 instance->common.te_last = duration; | ||||||
|  |             } else { | ||||||
|  |                 instance->common.parser_step = 0; | ||||||
|  |             } | ||||||
|  |         } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { | ||||||
|  |             if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) < | ||||||
|  |                instance->common.te_delta) { | ||||||
|  |                 // Found header
 | ||||||
|  |                 instance->common.header_count++; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) < | ||||||
|  |                 instance->common.te_delta) { | ||||||
|  |                 // Found start bit
 | ||||||
|  |                 if(instance->common.header_count > 40) { | ||||||
|  |                     instance->common.parser_step = 2; | ||||||
|  |                     instance->common.code_found = 0; | ||||||
|  |                     instance->common.code_count_bit = 0; | ||||||
|  |                 } else { | ||||||
|  |                     instance->common.parser_step = 0; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 instance->common.parser_step = 0; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->common.parser_step = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case 2: | ||||||
|  |         if(level) { | ||||||
|  |             instance->common.te_last = duration; | ||||||
|  |             instance->common.parser_step = 3; | ||||||
|  |         } else { | ||||||
|  |             instance->common.parser_step = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case 3: | ||||||
|  |         if(!level) { | ||||||
|  |             if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) { | ||||||
|  |                 //Found stop bit
 | ||||||
|  |                 instance->common.parser_step = 0; | ||||||
|  |                 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; | ||||||
|  |                     if(instance->common.callback) | ||||||
|  |                         instance->common.callback( | ||||||
|  |                             (SubGhzProtocolCommon*)instance, instance->common.context); | ||||||
|  |                 } | ||||||
|  |                 instance->common.code_found = 0; | ||||||
|  |                 instance->common.code_count_bit = 0; | ||||||
|  |                 instance->common.parser_step = 0; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->common.te_last, instance->common.te_short) < | ||||||
|  |                  instance->common.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { | ||||||
|  |                 subghz_protocol_common_add_bit(&instance->common, 0); | ||||||
|  |                 instance->common.parser_step = 2; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->common.te_last, instance->common.te_long) < | ||||||
|  |                  instance->common.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { | ||||||
|  |                 subghz_protocol_common_add_bit(&instance->common, 1); | ||||||
|  |                 instance->common.parser_step = 2; | ||||||
|  |             } else { | ||||||
|  |                 instance->common.parser_step = 0; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->common.parser_step = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output) { | ||||||
|  |     uint32_t code_found_hi = instance->common.code_last_found >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_common_reverse_key( | ||||||
|  |         instance->common.code_last_found, instance->common.code_last_count_bit); | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_reverse_hi = code_found_reverse >> 32; | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Yek:0x%lX%08lX\r\n", | ||||||
|  |         instance->common.name, | ||||||
|  |         instance->common.code_last_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_hi, | ||||||
|  |         code_found_reverse_lo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output) { | ||||||
|  |     uint32_t code_found_hi = instance->common.code_last_found >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_printf( | ||||||
|  |         output, | ||||||
|  |         "Protocol: %s\n" | ||||||
|  |         "Bit: %d\n" | ||||||
|  |         "Key: %08lX%08lX\n", | ||||||
|  |         instance->common.name, | ||||||
|  |         instance->common.code_last_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_nero_radio_to_load_protocol_from_file( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     SubGhzProtocolNeroRadio* instance) { | ||||||
|  |     bool loaded = false; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  |     int res = 0; | ||||||
|  |     int data = 0; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // Read and parse bit data from 2nd line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); | ||||||
|  |         if(res != 1) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         instance->common.code_last_count_bit = (uint8_t)data; | ||||||
|  | 
 | ||||||
|  |         // Read and parse key data from 3nd line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         // strlen("Key: ") = 5
 | ||||||
|  |         string_right(temp_str, 5); | ||||||
|  | 
 | ||||||
|  |         uint8_t buf_key[8] = {0}; | ||||||
|  |         if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for(uint8_t i = 0; i < 8; i++) { | ||||||
|  |             instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         loaded = true; | ||||||
|  |     } while(0); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|  | 
 | ||||||
|  |     return loaded; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     furi_assert(instance); | ||||||
|  |     SubGhzProtocolCommonLoad* data = context; | ||||||
|  |     instance->common.code_last_found = data->code_found; | ||||||
|  |     instance->common.code_last_count_bit = data->code_count_bit; | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								lib/subghz/protocols/subghz_protocol_nero_radio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/subghz/protocols/subghz_protocol_nero_radio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "subghz_protocol_common.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolNeroRadio SubGhzProtocolNeroRadio; | ||||||
|  | 
 | ||||||
|  | /** Allocate SubGhzProtocolNeroRadio
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzProtocolNeroRadio*  | ||||||
|  |  */ | ||||||
|  | SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(); | ||||||
|  | 
 | ||||||
|  | /** Free SubGhzProtocolNeroRadio
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance); | ||||||
|  | 
 | ||||||
|  | /** Get upload protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio instance | ||||||
|  |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
|  | bool subghz_protocol_nero_radio_send_key(SubGhzProtocolNeroRadio* instance, SubGhzProtocolCommonEncoder* encoder); | ||||||
|  | 
 | ||||||
|  | /** Reset internal state
 | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio instance | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance); | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolNeroRadio instance | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance); | ||||||
|  | 
 | ||||||
|  | /** Parse accepted duration
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio instance | ||||||
|  |  * @param data - LevelDuration level_duration | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_parse(SubGhzProtocolNeroRadio* instance, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | /** Outputting information from the parser
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio* instance | ||||||
|  |  * @param output   - output string | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolNeroRadio instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
|  | bool subghz_protocol_nero_radio_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroRadio* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNeroRadio instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
|  | void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context); | ||||||
| @ -18,7 +18,7 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance); | |||||||
| 
 | 
 | ||||||
| /** Get upload protocol
 | /** Get upload protocol
 | ||||||
|  *  |  *  | ||||||
|  * @param instance - SubGhzProtocolCame instance |  * @param instance - SubGhzProtocolNeroSketch instance | ||||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  * @return bool |  * @return bool | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance); | |||||||
| 
 | 
 | ||||||
| /** Get upload protocol
 | /** Get upload protocol
 | ||||||
|  *  |  *  | ||||||
|  * @param instance - SubGhzProtocolCame instance |  * @param instance - SubGhzProtocolNiceFlo instance | ||||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  * @return bool |  * @return bool | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -172,7 +172,7 @@ void subghz_decoder_princeton_parse( | |||||||
|         if(!level) { |         if(!level) { | ||||||
|             if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { |             if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { | ||||||
|                 instance->common.parser_step = 1; |                 instance->common.parser_step = 1; | ||||||
|                 if(instance->common.code_count_bit >= |                 if(instance->common.code_count_bit == | ||||||
|                    instance->common.code_min_count_bit_for_found) { |                    instance->common.code_min_count_bit_for_found) { | ||||||
|                     if(instance->common.code_last_found == instance->common.code_found) { |                     if(instance->common.code_last_found == instance->common.code_found) { | ||||||
|                         //instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging
 |                         //instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging
 | ||||||
|  | |||||||
| @ -282,9 +282,9 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t | |||||||
|     string_cat_printf( |     string_cat_printf( | ||||||
|         output, |         output, | ||||||
|         "%s %dbit\r\n" |         "%s %dbit\r\n" | ||||||
|         "Key:0x%lX%lX\r\n" |         "Key:%08lX%08lX\r\n" | ||||||
|         "Fix:0x%08lX     Cnt:%04X\r\n" |         "Fix:0x%08lX    Cnt:%04X\r\n" | ||||||
|         "Hop:0x%08lX     Btn:%02lX\r\n" |         "Hop:0x%08lX    Btn:%02lX\r\n" | ||||||
|         "MF:%s\r\n" |         "MF:%s\r\n" | ||||||
|         "Sn:0x%07lX \r\n", |         "Sn:0x%07lX \r\n", | ||||||
|         instance->common.name, |         instance->common.name, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm