[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, 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)) { | ||||
|                 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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     furi_assert(variable_item_list); | ||||
|     return variable_item_list->view; | ||||
|  | ||||
| @ -18,6 +18,9 @@ VariableItemList* variable_item_list_alloc(); | ||||
|  * @param variable_item_list VariableItemList instance | ||||
|  */ | ||||
| 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); | ||||
| 
 | ||||
| /** 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( | ||||
|     Widget* widget, | ||||
|     uint8_t x, | ||||
|  | ||||
| @ -26,6 +26,23 @@ void widget_clear(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
 | ||||
|  * @param widget Widget instance | ||||
|  * @param x - x coordinate | ||||
|  | ||||
| @ -30,7 +30,18 @@ static bool gui_button_input(InputEvent* event, WidgetElement* element) { | ||||
|     GuiButtonModel* model = element->model; | ||||
|     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)) { | ||||
|             model->callback(model->button_type, model->context); | ||||
|             consumed = true; | ||||
|  | ||||
| @ -6,6 +6,8 @@ typedef enum { | ||||
|     GuiButtonTypeLeft, | ||||
|     GuiButtonTypeCenter, | ||||
|     GuiButtonTypeRight, | ||||
|     GuiButtonTypeCenterPress, | ||||
|     GuiButtonTypeCenterRelease, | ||||
| } GuiButtonType; | ||||
| 
 | ||||
| typedef void (*ButtonCallback)(GuiButtonType result, void* context); | ||||
| @ -28,6 +30,15 @@ struct WidgetElement { | ||||
|     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 */ | ||||
| WidgetElement* widget_element_string_create( | ||||
|     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, receiver, Receiver) | ||||
| ADD_SCENE(subghz, receiver_config, ReceiverConfig) | ||||
| ADD_SCENE(subghz, receiver_info, ReceiverInfo) | ||||
| ADD_SCENE(subghz, save_name, SaveName) | ||||
| ADD_SCENE(subghz, save_success, SaveSuccess) | ||||
| ADD_SCENE(subghz, saved, Saved) | ||||
| ADD_SCENE(subghz, transmitter, Transmitter) | ||||
| ADD_SCENE(subghz, no_man, NoMan) | ||||
| ADD_SCENE(subghz, show_error, ShowError) | ||||
| ADD_SCENE(subghz, test, Test) | ||||
| ADD_SCENE(subghz, test_static, TestStatic) | ||||
| ADD_SCENE(subghz, test_carrier, TestCarrier) | ||||
|  | ||||
| @ -1,21 +1,102 @@ | ||||
| #include "../subghz_i.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) { | ||||
|     furi_assert(context); | ||||
|     SubGhz* subghz = context; | ||||
|     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) { | ||||
|     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; | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| @ -24,51 +105,43 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         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: | ||||
|             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; | ||||
|             break; | ||||
|         case SubghzReceverEventSendStart: | ||||
|             subghz->state_notifications = NOTIFICATION_TX_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); | ||||
|             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; | ||||
|         case SubghzReceverEventOK: | ||||
|             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); | ||||
|             return true; | ||||
|             break; | ||||
|         case SubghzReceverEventConfig: | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             return true; | ||||
|             break; | ||||
|         case SubghzReceverEventSendHistoryFull: | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); | ||||
|             return true; | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     } 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) { | ||||
|         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; | ||||
|  | ||||
							
								
								
									
										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.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); | ||||
|                 return true; | ||||
|             } else { | ||||
|                 //Error save
 | ||||
|                 string_set(subghz->error_str, "No name file"); | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -8,15 +8,18 @@ enum SubmenuIndex { | ||||
|     SubmenuIndexCAME12bit, | ||||
|     SubmenuIndexCAME24bit, | ||||
|     SubmenuIndexNeroSketch, | ||||
|     SubmenuIndexNeroRadio, | ||||
|     SubmenuIndexGateTX, | ||||
|     SubmenuIndexDoorHan, | ||||
| }; | ||||
| 
 | ||||
| bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { | ||||
|     SubGhz* subghz = context; | ||||
|     subghz->protocol_result = subghz_protocol_get_by_name(subghz->protocol, protocol_name); | ||||
|     if(subghz->protocol_result == NULL) { | ||||
|         //show error
 | ||||
|     subghz->txrx->protocol_result = | ||||
|         subghz_protocol_get_by_name(subghz->txrx->protocol, protocol_name); | ||||
|     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 true; | ||||
| @ -62,6 +65,8 @@ const void subghz_scene_set_type_on_enter(void* context) { | ||||
|         subghz); | ||||
|     // submenu_add_item(
 | ||||
|     //     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( | ||||
|         subghz->submenu, | ||||
|         "Gate TX_433", | ||||
| @ -90,81 +95,86 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event | ||||
|         switch(event.event) { | ||||
|         case SubmenuIndexPricenton: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = key; | ||||
|                 subghz->txrx->protocol_result->code_last_found = key; | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexNiceFlo12bit: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = key; | ||||
|                 subghz->txrx->protocol_result->code_last_found = key; | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexNiceFlo24bit: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = key; | ||||
|                 subghz->txrx->protocol_result->code_last_found = key; | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexCAME12bit: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = key; | ||||
|                 subghz->txrx->protocol_result->code_last_found = key; | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexCAME24bit: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = key; | ||||
|                 subghz->txrx->protocol_result->code_last_found = key; | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         // case SubmenuIndexNeroSketch:
 | ||||
|         //     /* code */
 | ||||
|         //     break;
 | ||||
|         // case SubmenuIndexNeroRadio:
 | ||||
|         //     /* code */
 | ||||
|         //     break;
 | ||||
|         case SubmenuIndexGateTX: | ||||
|             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
 | ||||
|                 subghz->protocol_result->code_last_found = subghz_protocol_common_reverse_key( | ||||
|                     key, subghz->protocol_result->code_last_count_bit); | ||||
|                 subghz->txrx->protocol_result->code_last_found = | ||||
|                     subghz_protocol_common_reverse_key( | ||||
|                         key, subghz->txrx->protocol_result->code_last_count_bit); | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexDoorHan: | ||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) { | ||||
|                 subghz->protocol_result->code_last_count_bit = 64; | ||||
|                 subghz->protocol_result->serial = key & 0x0FFFFFFF; | ||||
|                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 | ||||
|                 subghz->protocol_result->cnt = 0x0003; | ||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 64; | ||||
|                 subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF; | ||||
|                 subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 | ||||
|                 subghz->txrx->protocol_result->cnt = 0x0003; | ||||
|                 if(subghz_protocol_keeloq_set_manufacture_name( | ||||
|                        subghz->protocol_result, "DoorHan")) { | ||||
|                     subghz->protocol_result->code_last_found = | ||||
|                         subghz_protocol_keeloq_gen_key(subghz->protocol_result); | ||||
|                        subghz->txrx->protocol_result, "DoorHan")) { | ||||
|                     subghz->txrx->protocol_result->code_last_found = | ||||
|                         subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result); | ||||
|                     generated_protocol = true; | ||||
|                 } else { | ||||
|                     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; | ||||
| 
 | ||||
|         default: | ||||
|             return false; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if(generated_protocol) { | ||||
|             subghz->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||
|             subghz->preset = FuriHalSubGhzPresetOok650Async; | ||||
|             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||
|             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -2,26 +2,26 @@ | ||||
| 
 | ||||
| #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; | ||||
|     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; | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = subghz->popup; | ||||
|     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_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); | ||||
|     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; | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| const void subghz_scene_no_man_on_exit(void* context) { | ||||
| const void subghz_scene_show_error_on_exit(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     // Clear view
 | ||||
| @ -45,4 +45,5 @@ const void subghz_scene_no_man_on_exit(void* context) { | ||||
|     popup_set_context(popup, NULL); | ||||
|     popup_set_timeout(popup, 0); | ||||
|     popup_disable_timeout(popup); | ||||
|     string_clean(subghz->error_str); | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include "../views/subghz_transmitter.h" | ||||
| #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||
| 
 | ||||
| void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* 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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     SubGhz* subghz = context; | ||||
|     SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; | ||||
| 
 | ||||
|     subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||
|     subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); | ||||
|     subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||
| 
 | ||||
|     subghz_transmitter_set_callback( | ||||
|         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||
|     subghz_scene_transmitter_update_data_show(subghz); | ||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||
| } | ||||
| 
 | ||||
| const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubghzTransmitterEventSendStart) { | ||||
|             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; | ||||
|         } else if(event.event == SubghzTransmitterEventSendStop) { | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz_transmitter_tx_stop(subghz); | ||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||
|                 subghz_tx_stop(subghz); | ||||
|                 subghz_sleep(); | ||||
|                 subghz->txrx->txrx_state = SubGhzTxRxStateIdle; | ||||
|             } | ||||
|             return true; | ||||
|         } else if(event.event == SubghzTransmitterEventBack) { | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 subghz->scene_manager, SubGhzSceneStart); | ||||
|             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) { | ||||
|         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) { | ||||
|     SubGhz* subghz = context; | ||||
|     SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; | ||||
|     subghz_transmitter_set_callback(subghz_transmitter, NULL, subghz); | ||||
| 
 | ||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,22 @@ | ||||
| #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[] = { | ||||
|     /* 300 - 348 */ | ||||
|     300000000, | ||||
| @ -20,7 +37,15 @@ const uint32_t subghz_frequencies[] = { | ||||
|     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_hopper_frequencies_count = | ||||
|     sizeof(subghz_hopper_frequencies) / sizeof(uint32_t); | ||||
| const uint32_t subghz_frequencies_433_92 = 5; | ||||
| 
 | ||||
| bool subghz_custom_event_callback(void* context, uint32_t event) { | ||||
| @ -77,11 +102,6 @@ SubGhz* subghz_alloc() { | ||||
|         SubGhzViewReceiver, | ||||
|         subghz_receiver_get_view(subghz->subghz_receiver)); | ||||
| 
 | ||||
|     // Dialog
 | ||||
|     subghz->dialog_ex = dialog_ex_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         subghz->view_dispatcher, SubGhzViewDialogEx, dialog_ex_get_view(subghz->dialog_ex)); | ||||
| 
 | ||||
|     // Popup
 | ||||
|     subghz->popup = popup_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -92,6 +112,11 @@ SubGhz* subghz_alloc() { | ||||
|     view_dispatcher_add_view( | ||||
|         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
 | ||||
|     subghz->subghz_transmitter = subghz_transmitter_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -99,6 +124,13 @@ SubGhz* subghz_alloc() { | ||||
|         SubGhzViewTransmitter, | ||||
|         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
 | ||||
|     subghz->subghz_test_carrier = subghz_test_carrier_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -120,17 +152,26 @@ SubGhz* subghz_alloc() { | ||||
|         SubGhzViewStatic, | ||||
|         subghz_test_static_get_view(subghz->subghz_test_static)); | ||||
| 
 | ||||
|     //init Worker & Protocol
 | ||||
|     subghz->worker = subghz_worker_alloc(); | ||||
|     subghz->protocol = subghz_protocol_alloc(); | ||||
|     //init Worker & Protocol & History
 | ||||
|     subghz->txrx = furi_alloc(sizeof(SubGhzTxRx)); | ||||
|     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, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); | ||||
|         subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); | ||||
|     subghz_worker_set_pair_callback( | ||||
|         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); | ||||
|     subghz_worker_set_context(subghz->worker, subghz->protocol); | ||||
|         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); | ||||
|     subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->protocol); | ||||
| 
 | ||||
|     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes"); | ||||
|     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx"); | ||||
|     //Init Error_str
 | ||||
|     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);
 | ||||
| 
 | ||||
| @ -160,18 +201,22 @@ void subghz_free(SubGhz* subghz) { | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); | ||||
|     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); | ||||
|     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
 | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); | ||||
|     submenu_free(subghz->submenu); | ||||
| 
 | ||||
|     // DialogEx
 | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewDialogEx); | ||||
|     dialog_ex_free(subghz->dialog_ex); | ||||
| 
 | ||||
|     // Popup
 | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); | ||||
|     popup_free(subghz->popup); | ||||
| @ -186,9 +231,14 @@ void subghz_free(SubGhz* subghz) { | ||||
|     furi_record_close("gui"); | ||||
|     subghz->gui = NULL; | ||||
| 
 | ||||
|     //Worker & Protocol
 | ||||
|     subghz_protocol_free(subghz->protocol); | ||||
|     subghz_worker_free(subghz->worker); | ||||
|     //Worker & Protocol & History
 | ||||
|     subghz_protocol_free(subghz->txrx->protocol); | ||||
|     subghz_worker_free(subghz->txrx->worker); | ||||
|     subghz_history_free(subghz->txrx->history); | ||||
|     free(subghz->txrx); | ||||
| 
 | ||||
|     //Error string
 | ||||
|     string_clear(subghz->error_str); | ||||
| 
 | ||||
|     // Notifications
 | ||||
|     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(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)) && | ||||
|        ((millis() - instance->last_update_timestamp) < 500)) { | ||||
|         instance->last_update_timestamp = millis(); | ||||
|         return; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; | ||||
|     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].manufacture_name = NULL; | ||||
|     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->last_index_write++; | ||||
|     return true; | ||||
| } | ||||
| @ -1,3 +1,4 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #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 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
 | ||||
|  *  | ||||
| @ -104,3 +112,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | ||||
|  * @return SubGhzProtocolCommonLoad* | ||||
|  */ | ||||
| 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) { | ||||
|     furi_assert(context); | ||||
|     if(!furi_hal_subghz_is_frequency_valid(frequency)) { | ||||
|         furi_check(0); | ||||
|     } | ||||
|     SubGhzWorker* worker = context; | ||||
| 
 | ||||
|     furi_hal_subghz_idle(); | ||||
| @ -33,6 +36,9 @@ uint32_t subghz_rx(void* context, 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(); | ||||
|     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); | ||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||
| @ -53,6 +59,7 @@ void subghz_rx_end(void* context) { | ||||
|         subghz_worker_stop(worker); | ||||
|         furi_hal_subghz_stop_async_rx(); | ||||
|     } | ||||
|     furi_hal_subghz_idle(); | ||||
| } | ||||
| 
 | ||||
| void subghz_sleep(void) { | ||||
| @ -66,41 +73,46 @@ void subghz_frequency_preset_to_str(void* context, string_t output) { | ||||
|         output, | ||||
|         "Frequency: %d\n" | ||||
|         "Preset: %d\n", | ||||
|         (int)subghz->frequency, | ||||
|         (int)subghz->preset); | ||||
|         (int)subghz->txrx->frequency, | ||||
|         (int)subghz->txrx->preset); | ||||
| } | ||||
| 
 | ||||
| void subghz_transmitter_tx_start(void* context) { | ||||
| void subghz_tx_start(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhz* subghz = context; | ||||
|     subghz->encoder = subghz_protocol_encoder_common_alloc(); | ||||
|     subghz->encoder->repeat = 200; //max repeat with the button held down
 | ||||
|     subghz->txrx->encoder = subghz_protocol_encoder_common_alloc(); | ||||
|     subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
 | ||||
|     //get upload
 | ||||
|     if(subghz->protocol_result->get_upload_protocol) { | ||||
|         if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) { | ||||
|             if(subghz->preset) { | ||||
|                 subghz_begin(subghz->preset); | ||||
|     if(subghz->txrx->protocol_result->get_upload_protocol) { | ||||
|         if(subghz->txrx->protocol_result->get_upload_protocol( | ||||
|                subghz->txrx->protocol_result, subghz->txrx->encoder)) { | ||||
|             if(subghz->txrx->preset) { | ||||
|                 subghz_begin(subghz->txrx->preset); | ||||
|             } else { | ||||
|                 subghz_begin(FuriHalSubGhzPresetOok650Async); | ||||
|                 subghz_begin(FuriHalSubGhzPresetOok270Async); | ||||
|             } | ||||
|             if(subghz->frequency) { | ||||
|                 subghz_tx(subghz->frequency); | ||||
|             if(subghz->txrx->frequency) { | ||||
|                 subghz_tx(subghz->txrx->frequency); | ||||
|             } else { | ||||
|                 subghz_tx(433920000); | ||||
|             } | ||||
| 
 | ||||
|             //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; | ||||
|     //Stop 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(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); | ||||
|     } | ||||
|     notification_message(subghz->notifications, &sequence_reset_red); | ||||
| @ -133,7 +145,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | ||||
|         if(res != 1) { | ||||
|             break; | ||||
|         } | ||||
|         subghz->frequency = (uint32_t)data; | ||||
|         subghz->txrx->frequency = (uint32_t)data; | ||||
| 
 | ||||
|         // Read and parse preset from 2st line
 | ||||
|         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) { | ||||
|             break; | ||||
|         } | ||||
|         subghz->preset = (FuriHalSubGhzPreset)data; | ||||
|         subghz->txrx->preset = (FuriHalSubGhzPreset)data; | ||||
| 
 | ||||
|         // Read and parse name protocol from 2st line
 | ||||
|         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
 | ||||
|         string_right(temp_str, 10); | ||||
|         subghz->protocol_result = | ||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); | ||||
|         if(subghz->protocol_result == NULL) { | ||||
|         subghz->txrx->protocol_result = | ||||
|             subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); | ||||
|         if(subghz->txrx->protocol_result == NULL) { | ||||
|             break; | ||||
|         } | ||||
|         if(!subghz->protocol_result->to_load_protocol_from_file( | ||||
|                file_worker, subghz->protocol_result)) { | ||||
|         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( | ||||
|                file_worker, subghz->txrx->protocol_result)) { | ||||
|             break; | ||||
|         } | ||||
|         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) { | ||||
|     furi_assert(context); | ||||
|     SubGhz* subghz = context; | ||||
|     furi_assert(subghz->protocol_result); | ||||
|     furi_assert(subghz->txrx->protocol_result); | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     string_t 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; | ||||
|         } | ||||
|         //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
 | ||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { | ||||
|             break; | ||||
| @ -276,7 +289,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | ||||
|         if(sscanf_res != 1) { | ||||
|             break; | ||||
|         } | ||||
|         subghz->frequency = (uint32_t)data; | ||||
|         subghz->txrx->frequency = (uint32_t)data; | ||||
| 
 | ||||
|         // Read and parse preset from 2st line
 | ||||
|         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) { | ||||
|             break; | ||||
|         } | ||||
|         subghz->preset = (FuriHalSubGhzPreset)data; | ||||
|         subghz->txrx->preset = (FuriHalSubGhzPreset)data; | ||||
| 
 | ||||
|         // Read and parse name protocol from 3st line
 | ||||
|         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
 | ||||
|         string_right(temp_str, 10); | ||||
|         subghz->protocol_result = | ||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); | ||||
|         if(subghz->protocol_result == NULL) { | ||||
|         subghz->txrx->protocol_result = | ||||
|             subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); | ||||
|         if(subghz->txrx->protocol_result == NULL) { | ||||
|             break; | ||||
|         } | ||||
|         if(!subghz->protocol_result->to_load_protocol_from_file( | ||||
|                file_worker, subghz->protocol_result)) { | ||||
|         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( | ||||
|                file_worker, subghz->txrx->protocol_result)) { | ||||
|             break; | ||||
|         } | ||||
|         res = true; | ||||
| @ -328,3 +341,57 @@ uint32_t subghz_random_serial(void) { | ||||
|     } | ||||
|     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 <gui/view_dispatcher.h> | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <gui/modules/dialog_ex.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include <gui/modules/text_input.h> | ||||
| #include <gui/modules/widget.h> | ||||
| 
 | ||||
| #include <subghz/scenes/subghz_scene.h> | ||||
| 
 | ||||
| @ -26,6 +26,8 @@ | ||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||
| #include "subghz_history.h" | ||||
| 
 | ||||
| #include <gui/modules/variable-item-list.h> | ||||
| 
 | ||||
| #define SUBGHZ_TEXT_STORE_SIZE 128 | ||||
| 
 | ||||
| #define NOTIFICATION_STARTING_STATE 0u | ||||
| @ -33,48 +35,81 @@ | ||||
| #define NOTIFICATION_TX_STATE 2u | ||||
| #define NOTIFICATION_RX_STATE 3u | ||||
| 
 | ||||
| extern const char* const subghz_frequencies_text[]; | ||||
| 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_hopper_frequencies_count; | ||||
| extern const uint32_t subghz_frequencies_433_92; | ||||
| 
 | ||||
| struct SubGhz { | ||||
|     Gui* gui; | ||||
|     NotificationApp* notifications; | ||||
| /** SubGhzTxRx state */ | ||||
| typedef enum { | ||||
|     SubGhzTxRxStateIdle, | ||||
|     SubGhzTxRxStateRx, | ||||
|     SubGhzTxRxStateTx, | ||||
| } SubGhzTxRxState; | ||||
| 
 | ||||
| /** SubGhzHopperState state */ | ||||
| typedef enum { | ||||
|     SubGhzHopperStateOFF, | ||||
|     SubGhzHopperStateRunnig, | ||||
|     SubGhzHopperStatePause, | ||||
|     SubGhzHopperStateRSSITimeOut, | ||||
| } SubGhzHopperState; | ||||
| 
 | ||||
| struct SubGhzTxRx { | ||||
|     SubGhzWorker* worker; | ||||
|     SubGhzProtocol* protocol; | ||||
|     SubGhzProtocolCommon* protocol_result; | ||||
|     SubGhzProtocolCommonEncoder* encoder; | ||||
|     uint32_t frequency; | ||||
|     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; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
| 
 | ||||
|     Submenu* submenu; | ||||
|     DialogEx* dialog_ex; | ||||
|     Popup* popup; | ||||
|     TextInput* text_input; | ||||
|     Widget* widget; | ||||
|     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||
|     uint8_t state_notifications; | ||||
| 
 | ||||
|     SubghzReceiver* subghz_receiver; | ||||
|     SubghzTransmitter* subghz_transmitter; | ||||
|     VariableItemList* variable_item_list; | ||||
| 
 | ||||
|     SubghzTestStatic* subghz_test_static; | ||||
|     SubghzTestCarrier* subghz_test_carrier; | ||||
|     SubghzTestPacket* subghz_test_packet; | ||||
|     string_t error_str; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubGhzViewMenu, | ||||
| 
 | ||||
|     SubGhzViewDialogEx, | ||||
|     SubGhzViewReceiver, | ||||
|     SubGhzViewPopup, | ||||
|     SubGhzViewTextInput, | ||||
|     SubGhzViewWidget, | ||||
|     SubGhzViewTransmitter, | ||||
| 
 | ||||
|     SubGhzViewVariableItemList, | ||||
|     SubGhzViewStatic, | ||||
|     SubGhzViewTestCarrier, | ||||
|     SubGhzViewTestPacket, | ||||
| @ -86,8 +121,8 @@ uint32_t subghz_tx(uint32_t frequency); | ||||
| void subghz_idle(void); | ||||
| void subghz_rx_end(void* context); | ||||
| void subghz_sleep(void); | ||||
| void subghz_transmitter_tx_start(void* context); | ||||
| void subghz_transmitter_tx_stop(void* context); | ||||
| void subghz_tx_start(void* context); | ||||
| void subghz_tx_stop(void* context); | ||||
| bool subghz_key_load(SubGhz* subghz, const char* file_path); | ||||
| bool subghz_save_protocol_to_file(void* context, const char* dev_name); | ||||
| bool subghz_load_protocol_from_file(SubGhz* subghz); | ||||
|  | ||||
| @ -1,42 +1,32 @@ | ||||
| #include "subghz_receiver.h" | ||||
| #include "../subghz_i.h" | ||||
| #include <math.h> | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #include <input/input.h> | ||||
| #include <gui/elements.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||
| 
 | ||||
| #include <assets_icons.h> | ||||
| #include <m-string.h> | ||||
| #include <m-array.h> | ||||
| 
 | ||||
| #define FRAME_HEIGHT 12 | ||||
| #define MAX_LEN_PX 100 | ||||
| #define MENU_ITEMS 4 | ||||
| 
 | ||||
| #define COUNT_FREQUNCY_HOPPER 3 | ||||
| const uint32_t subghz_frequencies_hopper[] = { | ||||
|     /* 300 - 348 */ | ||||
|     315000000, | ||||
|     /* 387 - 464 */ | ||||
|     433920000, /* LPD433 mid */ | ||||
|     /* 779 - 928 */ | ||||
|     868350000, | ||||
| typedef struct { | ||||
|     string_t item_str; | ||||
|     uint8_t type; | ||||
| } SubGhzReceiverMenuItem; | ||||
| 
 | ||||
| ARRAY_DEF(SubGhzReceiverMenuItemArray, SubGhzReceiverMenuItem, M_POD_OPLIST) | ||||
| 
 | ||||
| #define M_OPL_SubGhzReceiverMenuItemArray_t() \ | ||||
|     ARRAY_OPLIST(SubGhzReceiverMenuItemArray, M_POD_OPLIST) | ||||
| 
 | ||||
| struct SubGhzReceiverHistory { | ||||
|     SubGhzReceiverMenuItemArray_t data; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     ReceiverSceneStart, | ||||
|     ReceiverSceneMain, | ||||
|     ReceiverSceneConfig, | ||||
|     ReceiverSceneInfo, | ||||
| } SubghzReceiverScene; | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubGhzHopperStateOFF, | ||||
|     SubGhzHopperStatePause, | ||||
|     SubGhzHopperStateRunnig, | ||||
|     SubGhzHopperStateRSSITimeOut, | ||||
| } SubGhzHopperState; | ||||
| typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; | ||||
| 
 | ||||
| static const Icon* ReceiverItemIcons[] = { | ||||
|     [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, | ||||
| @ -48,27 +38,16 @@ struct SubghzReceiver { | ||||
|     View* view; | ||||
|     SubghzReceiverCallback callback; | ||||
|     void* context; | ||||
|     SubGhzWorker* worker; | ||||
|     SubGhzProtocol* protocol; | ||||
|     osTimerId timer; | ||||
|     SubGhzHopperState hopper_state; | ||||
|     uint8_t hopper_timeout; | ||||
|     uint32_t event_key_sequence; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     string_t text; | ||||
|     uint16_t scene; | ||||
|     SubGhzProtocolCommon* protocol_result; | ||||
|     SubGhzHistory* history; | ||||
|     uint8_t frequency; | ||||
|     uint8_t temp_frequency; | ||||
|     uint32_t real_frequency; | ||||
| 
 | ||||
|     string_t frequency_str; | ||||
|     string_t preset_str; | ||||
|     string_t history_stat_str; | ||||
|     SubGhzReceiverHistory* history; | ||||
|     uint16_t idx; | ||||
|     uint16_t list_offset; | ||||
|     uint16_t history_item; | ||||
|     bool menu; | ||||
| } SubghzReceiverModel; | ||||
| 
 | ||||
| void subghz_receiver_set_callback( | ||||
| @ -81,35 +60,6 @@ void subghz_receiver_set_callback( | ||||
|     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) { | ||||
|     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) { | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); | ||||
| @ -144,163 +126,56 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll | ||||
| } | ||||
| 
 | ||||
| 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_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_str(canvas, 79, 62, string_get_cstr(model->preset_str)); | ||||
|     canvas_draw_str(canvas, 96, 62, string_get_cstr(model->history_stat_str)); | ||||
|     if(model->history_item == 0) { | ||||
|         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str(canvas, 63, 46, "Scanning..."); | ||||
|         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||
|         return; | ||||
|     } | ||||
|     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; | ||||
| 
 | ||||
|     switch(model->scene) { | ||||
|     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); | ||||
|         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[subghz_history_get_type_protocol(model->history, idx)]); | ||||
|         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); | ||||
|     } | ||||
|         canvas_set_color(canvas, ColorBlack); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
| 
 | ||||
|         elements_button_left(canvas, "Config"); | ||||
|         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||
|         if(subghz_history_get_text_space_left(model->history, str_buff)) { | ||||
|             canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff)); | ||||
|         } 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_set_font(canvas, FontPrimary); | ||||
|         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); | ||||
|         break; | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     uint8_t scene = 0; | ||||
|     SubghzReceiver* subghz_receiver = context; | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             scene = model->scene; | ||||
|             return false; | ||||
|         }); | ||||
| 
 | ||||
|     bool can_be_saved = false; | ||||
| 
 | ||||
|     switch(scene) { | ||||
|     case ReceiverSceneMain: | ||||
|     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||
|             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; | ||||
|         subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); | ||||
|     } else if( | ||||
|         event->key == InputKeyUp && | ||||
|         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||
| @ -314,292 +189,50 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | ||||
|         (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++; | ||||
|                 if(model->idx != model->history_item - 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; | ||||
|                 if(model->history_item != 0) { | ||||
|                     subghz_receiver->callback(SubghzReceverEventOK, subghz_receiver->context); | ||||
|                 } | ||||
|                     return true; | ||||
|                 }); | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     case ReceiverSceneInfo: | ||||
|         with_view_model( | ||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|                 can_be_saved = | ||||
|                     (model->protocol_result && model->protocol_result->to_save_string && | ||||
|                      strcmp(model->protocol_result->name, "KeeLoq")); | ||||
|                 return false; | ||||
|             }); | ||||
|         if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||
|             with_view_model( | ||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|                     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( | ||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|                 if(subghz_history_get_text_space_left(model->history, NULL)) { | ||||
|                     subghz_receiver_history_full(subghz_receiver); | ||||
|                 } | ||||
|                 return false; | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|     furi_assert(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); | ||||
|     //SubghzReceiver* subghz_receiver = context;
 | ||||
| } | ||||
| 
 | ||||
| void subghz_receiver_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubghzReceiver* subghz_receiver = context; | ||||
|     osTimerStop(subghz_receiver->timer); | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             string_clean(model->text); | ||||
|             return true; | ||||
|             string_clean(model->frequency_str); | ||||
|             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() { | ||||
| @ -616,14 +249,14 @@ SubghzReceiver* subghz_receiver_alloc() { | ||||
| 
 | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             string_init(model->text); | ||||
|             model->history = subghz_history_alloc(); | ||||
|             string_init(model->frequency_str); | ||||
|             string_init(model->preset_str); | ||||
|             string_init(model->history_stat_str); | ||||
|             model->history = furi_alloc(sizeof(SubGhzReceiverHistory)); | ||||
|             SubGhzReceiverMenuItemArray_init(model->history->data); | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     subghz_receiver->timer = | ||||
|         osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL); | ||||
|     subghz_receiver->hopper_state = SubGhzHopperStateOFF; | ||||
|     return subghz_receiver; | ||||
| } | ||||
| 
 | ||||
| @ -632,11 +265,18 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) { | ||||
| 
 | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             string_clear(model->text); | ||||
|             subghz_history_free(model->history); | ||||
|             string_clear(model->frequency_str); | ||||
|             string_clear(model->preset_str); | ||||
|             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); | ||||
|     free(subghz_receiver); | ||||
| } | ||||
| @ -646,43 +286,24 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { | ||||
|     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); | ||||
|     uint32_t frequency; | ||||
|     uint32_t idx = 0; | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             frequency = subghz_history_get_frequency(model->history, model->idx); | ||||
|             idx = model->idx; | ||||
|             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); | ||||
|     FuriHalSubGhzPreset preset; | ||||
|     with_view_model( | ||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||
|             preset = subghz_history_get_preset(model->history, model->idx); | ||||
|             return false; | ||||
|             model->idx = idx; | ||||
|             if(model->idx > 2) model->list_offset = idx - 2; | ||||
|             return true; | ||||
|         }); | ||||
|     return preset; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     subghz_receiver_update_offset(subghz_receiver); | ||||
| } | ||||
| @ -1,21 +1,11 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #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 { | ||||
|     SubghzReceverEventOK, | ||||
|     SubghzReceverEventConfig, | ||||
|     SubghzReceverEventMain, | ||||
|     SubghzReceverEventSave, | ||||
|     SubghzReceverEventBack, | ||||
|     SubghzReceverEventMore, | ||||
|     SubghzReceverEventSendStart, | ||||
|     SubghzReceverEventSendStop, | ||||
|     SubghzReceverEventSendHistoryFull, | ||||
| } SubghzReceverEvent; | ||||
| 
 | ||||
| typedef struct SubghzReceiver SubghzReceiver; | ||||
| @ -33,17 +23,19 @@ void subghz_receiver_free(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, | ||||
|     SubGhzProtocolCommon* protocol_result, | ||||
|     SubGhzProtocol* protocol); | ||||
|     const char* frequency_str, | ||||
|     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_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output); | ||||
| void subghz_receiver_exit(void* context); | ||||
| @ -1,13 +1,8 @@ | ||||
| #include "subghz_transmitter.h" | ||||
| #include "../subghz_i.h" | ||||
| 
 | ||||
| #include <math.h> | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| #include <input/input.h> | ||||
| #include <gui/elements.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||
| 
 | ||||
| struct SubghzTransmitter { | ||||
|     View* view; | ||||
| @ -16,11 +11,10 @@ struct SubghzTransmitter { | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     string_t text; | ||||
|     uint16_t scene; | ||||
|     uint32_t real_frequency; | ||||
|     FuriHalSubGhzPreset preset; | ||||
|     SubGhzProtocolCommon* protocol; | ||||
|     string_t frequency_str; | ||||
|     string_t preset_str; | ||||
|     string_t key_str; | ||||
|     uint8_t show_button; | ||||
| } SubghzTransmitterModel; | ||||
| 
 | ||||
| void subghz_transmitter_set_callback( | ||||
| @ -33,24 +27,19 @@ void subghz_transmitter_set_callback( | ||||
|     subghz_transmitter->context = context; | ||||
| } | ||||
| 
 | ||||
| void subghz_transmitter_set_protocol( | ||||
| void subghz_transmitter_add_data_to_show( | ||||
|     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( | ||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||
|             model->protocol = protocol; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|             string_set(model->key_str, key_str); | ||||
|             string_set(model->frequency_str, frequency_str); | ||||
|             string_set(model->preset_str, preset_str); | ||||
|             model->show_button = show_button; | ||||
|             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) { | ||||
|     char buffer[64]; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); | ||||
|     snprintf( | ||||
|         buffer, | ||||
|         sizeof(buffer), | ||||
|         "%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"); | ||||
|     } | ||||
|     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str)); | ||||
|     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str)); | ||||
|     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str)); | ||||
|     if(model->show_button) subghz_transmitter_button_right(canvas, "Send"); | ||||
| } | ||||
| 
 | ||||
| bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||
| @ -114,26 +90,25 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||
|     SubghzTransmitter* subghz_transmitter = context; | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     with_view_model( | ||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||
|             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 false; | ||||
|                 } | ||||
|             if(model->show_button) { | ||||
|                 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; | ||||
|         }); | ||||
|     //if(event->type != InputTypeShort) return false;
 | ||||
| 
 | ||||
|     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { | ||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); | ||||
| @ -146,37 +121,14 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void subghz_transmitter_text_callback(string_t text, void* context) { | ||||
|     furi_assert(context); | ||||
|     SubghzTransmitter* subghz_transmitter = context; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||
|             string_set(model->text, text); | ||||
|             model->scene = 0; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void subghz_transmitter_enter(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubghzTransmitter* subghz_transmitter = context; | ||||
|     with_view_model( | ||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||
|             string_clean(model->text); | ||||
|             model->protocol->to_string(model->protocol, model->text); | ||||
|             return true; | ||||
|         }); | ||||
|     // SubghzTransmitter* subghz_transmitter = context;
 | ||||
| } | ||||
| 
 | ||||
| void subghz_transmitter_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubghzTransmitter* subghz_transmitter = context; | ||||
|     with_view_model( | ||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||
|             string_clean(model->text); | ||||
|             return true; | ||||
|         }); | ||||
|     // SubghzTransmitter* subghz_transmitter = context;
 | ||||
| } | ||||
| 
 | ||||
| SubghzTransmitter* subghz_transmitter_alloc() { | ||||
| @ -194,7 +146,9 @@ SubghzTransmitter* subghz_transmitter_alloc() { | ||||
| 
 | ||||
|     with_view_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 subghz_transmitter; | ||||
| @ -205,7 +159,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { | ||||
| 
 | ||||
|     with_view_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; | ||||
|         }); | ||||
|     view_free(subghz_transmitter->view); | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubghzTransmitterEventSendStart, | ||||
| @ -25,10 +24,9 @@ void subghz_transmitter_free(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, | ||||
|     SubGhzProtocolCommon* protocol); | ||||
| void subghz_transmitter_set_frequency_preset( | ||||
|     SubghzTransmitter* subghz_transmitter, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset); | ||||
|     const char* key_str, | ||||
|     const char* frequency_str, | ||||
|     const char* preset_str, | ||||
|     uint8_t show_button); | ||||
|  | ||||
| @ -10,6 +10,7 @@ | ||||
| #include "subghz_protocol_faac_slh.h" | ||||
| #include "subghz_protocol_nero_sketch.h" | ||||
| #include "subghz_protocol_star_line.h" | ||||
| #include "subghz_protocol_nero_radio.h" | ||||
| 
 | ||||
| #include "../subghz_keystore.h" | ||||
| 
 | ||||
| @ -27,6 +28,7 @@ typedef enum { | ||||
|     SubGhzProtocolTypeFaacSLH, | ||||
|     SubGhzProtocolTypeNeroSketch, | ||||
|     SubGhzProtocolTypeStarLine, | ||||
|     SubGhzProtocolTypeNeroRadio, | ||||
| 
 | ||||
|     SubGhzProtocolTypeMax, | ||||
| } SubGhzProtocolType; | ||||
| @ -88,6 +90,8 @@ SubGhzProtocol* subghz_protocol_alloc() { | ||||
|         (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc(); | ||||
|     instance->protocols[SubGhzProtocolTypeStarLine] = | ||||
|         (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore); | ||||
|     instance->protocols[SubGhzProtocolTypeNeroRadio] = | ||||
|         (SubGhzProtocolCommon*)subghz_protocol_nero_radio_alloc(); | ||||
| 
 | ||||
|     return instance; | ||||
| } | ||||
| @ -113,6 +117,8 @@ void subghz_protocol_free(SubGhzProtocol* instance) { | ||||
|         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); | ||||
|     subghz_protocol_star_line_free( | ||||
|         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); | ||||
|     subghz_protocol_nero_radio_free( | ||||
|         (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); | ||||
| 
 | ||||
|     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) { | ||||
|     // subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name);
 | ||||
|     subghz_protocol_nice_flor_s_name_file( | ||||
|         (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); | ||||
| } | ||||
| @ -191,6 +196,8 @@ void subghz_protocol_reset(SubGhzProtocol* instance) { | ||||
|         (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); | ||||
|     subghz_protocol_star_line_reset( | ||||
|         (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); | ||||
|     subghz_protocol_nero_radio_reset( | ||||
|         (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     subghz_protocol_star_line_parse( | ||||
|         (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
 | ||||
|  *  | ||||
|  * @param instance - SubGhzProtocolCame instance | ||||
|  * @param instance - SubGhzProtocolGateTX instance | ||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||
|  * @return bool | ||||
|  */ | ||||
|  | ||||
| @ -398,7 +398,7 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp | ||||
|     string_cat_printf( | ||||
|         output, | ||||
|         "%s %dbit\r\n" | ||||
|         "Key:0x%lX%lX\r\n" | ||||
|         "Key:%08lX%08lX\r\n" | ||||
|         "Fix:0x%08lX    Cnt:%04X\r\n" | ||||
|         "Hop:0x%08lX    Btn:%02lX\r\n" | ||||
|         "MF:%s\r\n" | ||||
|  | ||||
| @ -49,7 +49,7 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context); | ||||
| 
 | ||||
| /** Get upload protocol
 | ||||
|  *  | ||||
|  * @param instance - SubGhzProtocolCame instance | ||||
|  * @param instance - SubGhzProtocolKeeloq instance | ||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||
|  * @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
 | ||||
|  *  | ||||
|  * @param instance - SubGhzProtocolCame instance | ||||
|  * @param instance - SubGhzProtocolNeroSketch instance | ||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||
|  * @return bool | ||||
|  */ | ||||
|  | ||||
| @ -18,7 +18,7 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance); | ||||
| 
 | ||||
| /** Get upload protocol
 | ||||
|  *  | ||||
|  * @param instance - SubGhzProtocolCame instance | ||||
|  * @param instance - SubGhzProtocolNiceFlo instance | ||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||
|  * @return bool | ||||
|  */ | ||||
|  | ||||
| @ -172,7 +172,7 @@ void subghz_decoder_princeton_parse( | ||||
|         if(!level) { | ||||
|             if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { | ||||
|                 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) { | ||||
|                     if(instance->common.code_last_found == instance->common.code_found) { | ||||
|                         //instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging
 | ||||
|  | ||||
| @ -282,7 +282,7 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t | ||||
|     string_cat_printf( | ||||
|         output, | ||||
|         "%s %dbit\r\n" | ||||
|         "Key:0x%lX%lX\r\n" | ||||
|         "Key:%08lX%08lX\r\n" | ||||
|         "Fix:0x%08lX    Cnt:%04X\r\n" | ||||
|         "Hop:0x%08lX    Btn:%02lX\r\n" | ||||
|         "MF:%s\r\n" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm