[FL-1756, FL-1769, FL-1776, FL-1759] Gui: input events complementary V3, refactoring. SubGhz: read/emulate fixes. Cleanup. (#684)
* Gui: move rotation logic to ViewPort, replace delayed View switch in ViewDispatcher with event filtering and redirection to previous view. * SubGhz: add function description * Gui, Input: add event id to input events. * SubGhz: fix "crashing on ?" * SubGhz: add icon scanning * SubGhz: updated interface read scene, updated interface config scene * Assets: update subghz assets * SubGhz: replaced the picture in the read scene, changed the paths to additional files * SubGhz: fix deadlock in timer callback * SubGhz: fix icon read scene * SubGhz: fix icon read scene * SubGhz: fix duble text transmitter scene * SubGhz: correct spelling. Gui: bigger queue for ViewDispatcher. * SubGhz: fix creation and transmission of dynamic code without the presence of a manufactory key * SubGhz: fix keelog, setting a name in the absence of a manufactory key * SubGhz: fix load bad keelog key * Format sources * Furi: remove garbage from core. GpioTester: fix memory leak and cleanup * Accessor: remove obsolete notification code * MusicPlayer: remove input event injection * Input: rename id to sequence Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									3ed26e61eb
								
							
						
					
					
						commit
						e17336498d
					
				| @ -35,7 +35,6 @@ AccessorApp::AccessorApp() | |||||||
|     : onewire_master{&ibutton_gpio} { |     : onewire_master{&ibutton_gpio} { | ||||||
|     furi_hal_power_insomnia_enter(); |     furi_hal_power_insomnia_enter(); | ||||||
|     notification = static_cast<NotificationApp*>(furi_record_open("notification")); |     notification = static_cast<NotificationApp*>(furi_record_open("notification")); | ||||||
|     notify_init(); |  | ||||||
|     furi_hal_power_enable_otg(); |     furi_hal_power_enable_otg(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -104,17 +103,6 @@ AccessorApp::Scene AccessorApp::get_previous_scene() { | |||||||
| 
 | 
 | ||||||
| /***************************** NOTIFY *******************************/ | /***************************** NOTIFY *******************************/ | ||||||
| 
 | 
 | ||||||
| void AccessorApp::notify_init() { |  | ||||||
|     GPIO_InitTypeDef GPIO_InitStruct = {0}; |  | ||||||
| 
 |  | ||||||
|     GPIO_InitStruct.Pin = PB3_Pin; |  | ||||||
|     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |  | ||||||
|     GPIO_InitStruct.Pull = GPIO_NOPULL; |  | ||||||
|     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; |  | ||||||
|     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; |  | ||||||
|     HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AccessorApp::notify_green_blink() { | void AccessorApp::notify_green_blink() { | ||||||
|     notification_message(notification, &sequence_blink_green_10); |     notification_message(notification, &sequence_blink_green_10); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,9 +29,7 @@ public: | |||||||
|     bool switch_to_previous_scene(uint8_t count = 1); |     bool switch_to_previous_scene(uint8_t count = 1); | ||||||
|     Scene get_previous_scene(); |     Scene get_previous_scene(); | ||||||
| 
 | 
 | ||||||
|     void notify_init(); |  | ||||||
|     void notify_green_blink(); |     void notify_green_blink(); | ||||||
| 
 |  | ||||||
|     void notify_success(); |     void notify_success(); | ||||||
| 
 | 
 | ||||||
|     char* get_text_store(); |     char* get_text_store(); | ||||||
|  | |||||||
| @ -2,143 +2,134 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <input/input.h> |  | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     const char* name; |     const char* name; | ||||||
|     GpioPin pin; |     const GpioPin* pin; | ||||||
| } GpioItem; | } GpioItem; | ||||||
| 
 | 
 | ||||||
| const GpioItem GPIO_PINS[] = { | static const GpioItem GPIO_PINS[] = { | ||||||
|     {"1.2: PA7", {GPIOA, GPIO_PIN_7}}, |     {"1.2: PA7", &gpio_ext_pa7}, | ||||||
|     {"1.3: PA6", {GPIOA, GPIO_PIN_6}}, |     {"1.3: PA6", &gpio_ext_pa6}, | ||||||
|     {"1.4: PA4", {GPIOA, GPIO_PIN_4}}, |     {"1.4: PA4", &gpio_ext_pa4}, | ||||||
|     {"1.5: PB3", {GPIOB, GPIO_PIN_3}}, |     {"1.5: PB3", &gpio_ext_pb3}, | ||||||
|     {"1.6: PB2", {GPIOB, GPIO_PIN_2}}, |     {"1.6: PB2", &gpio_ext_pb2}, | ||||||
|     {"1.7: PC3", {GPIOC, GPIO_PIN_3}}, |     {"1.7: PC3", &gpio_ext_pc3}, | ||||||
| 
 |     {"2.7: PC1", &gpio_ext_pc1}, | ||||||
|     {"2.7: PC1", {GPIOC, GPIO_PIN_1}}, |     {"2.8: PC0", &gpio_ext_pc0}, | ||||||
|     {"2.8: PC0", {GPIOC, GPIO_PIN_0}}, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); | ||||||
|     EventTypeTick, |  | ||||||
|     EventTypeKey, |  | ||||||
| } EventType; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     union { |  | ||||||
|         InputEvent input; |  | ||||||
|     } value; |  | ||||||
|     EventType type; |  | ||||||
| } AppEvent; |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     osMessageQueueId_t input_queue; | ||||||
|     uint8_t gpio_index; |     uint8_t gpio_index; | ||||||
| } State; |     ViewPort* view_port; | ||||||
|  |     Gui* gui; | ||||||
|  |     NotificationApp* notification; | ||||||
|  | } GpioTest; | ||||||
| 
 | 
 | ||||||
| static void render_callback(Canvas* canvas, void* ctx) { | static void gpio_test_render_callback(Canvas* canvas, void* ctx) { | ||||||
|     State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); |     GpioTest* gpio_test = ctx; | ||||||
| 
 | 
 | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
|     canvas_draw_str(canvas, 2, 10, "GPIO Control"); |     canvas_draw_str(canvas, 2, 10, "GPIO Control"); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     canvas_draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name); |     canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name); | ||||||
| 
 |  | ||||||
|     release_mutex((ValueMutex*)ctx, state); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void input_callback(InputEvent* input_event, void* ctx) { | static void gpio_test_input_callback(InputEvent* input_event, void* ctx) { | ||||||
|     osMessageQueueId_t event_queue = ctx; |     GpioTest* gpio_test = ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0); | ||||||
|     event.type = EventTypeKey; | } | ||||||
|     event.value.input = *input_event; | 
 | ||||||
|     osMessageQueuePut(event_queue, &event, 0, 0); | static void gpio_test_configure_pins(GpioMode mode) { | ||||||
|  |     for(size_t i = 0; i < GPIO_PINS_COUNT; i++) { | ||||||
|  |         hal_gpio_write(GPIO_PINS[i].pin, false); | ||||||
|  |         hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedLow); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GpioTest* gpio_test_alloc() { | ||||||
|  |     GpioTest* instance = furi_alloc(sizeof(GpioTest)); | ||||||
|  | 
 | ||||||
|  |     gpio_test_configure_pins(GpioModeOutputPushPull); | ||||||
|  | 
 | ||||||
|  |     instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); | ||||||
|  |     furi_check(instance->input_queue); | ||||||
|  | 
 | ||||||
|  |     instance->view_port = view_port_alloc(); | ||||||
|  |     view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance); | ||||||
|  |     view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance); | ||||||
|  | 
 | ||||||
|  |     instance->gui = furi_record_open("gui"); | ||||||
|  |     gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); | ||||||
|  | 
 | ||||||
|  |     instance->notification = furi_record_open("notification"); | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void gpio_test_free(GpioTest* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("notification"); | ||||||
|  | 
 | ||||||
|  |     view_port_enabled_set(instance->view_port, false); | ||||||
|  |     gui_remove_view_port(instance->gui, instance->view_port); | ||||||
|  |     furi_record_close("gui"); | ||||||
|  | 
 | ||||||
|  |     view_port_free(instance->view_port); | ||||||
|  | 
 | ||||||
|  |     osMessageQueueDelete(instance->input_queue); | ||||||
|  | 
 | ||||||
|  |     gpio_test_configure_pins(GpioModeAnalog); | ||||||
|  | 
 | ||||||
|  |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t gpio_test_app(void* p) { | int32_t gpio_test_app(void* p) { | ||||||
|     osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); |     GpioTest* gpio_test = gpio_test_alloc(); | ||||||
|     furi_check(event_queue); |  | ||||||
| 
 | 
 | ||||||
|     State _state; |     InputEvent event; | ||||||
|     _state.gpio_index = 0; |     while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) { | ||||||
| 
 |         if(event.type == InputTypeShort) { | ||||||
|     ValueMutex state_mutex; |             if(event.key == InputKeyBack) { | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(State))) { |                 notification_message(gpio_test->notification, &sequence_reset_green); | ||||||
|         printf("[gpio-tester] cannot create mutex\r\n"); |                 break; | ||||||
|         return 255; |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|     ViewPort* view_port = view_port_alloc(); |             if(event.key == InputKeyRight) { | ||||||
| 
 |                 if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) { | ||||||
|     view_port_draw_callback_set(view_port, render_callback, &state_mutex); |                     gpio_test->gpio_index++; | ||||||
|     view_port_input_callback_set(view_port, input_callback, event_queue); |  | ||||||
| 
 |  | ||||||
|     // Open GUI and register view_port
 |  | ||||||
|     Gui* gui = furi_record_open("gui"); |  | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |  | ||||||
| 
 |  | ||||||
|     NotificationApp* notification = furi_record_open("notification"); |  | ||||||
| 
 |  | ||||||
|     // configure pin
 |  | ||||||
|     for(uint8_t i = 0; i < sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); i++) { |  | ||||||
|         hal_gpio_init( |  | ||||||
|             (GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     AppEvent event; |  | ||||||
|     while(1) { |  | ||||||
|         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever); |  | ||||||
|         State* state = (State*)acquire_mutex_block(&state_mutex); |  | ||||||
| 
 |  | ||||||
|         if(event_status == osOK) { |  | ||||||
|             if(event.type == EventTypeKey) { |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyBack) { |  | ||||||
|                     printf("[gpio-tester] bye!\r\n"); |  | ||||||
|                     notification_message(notification, &sequence_reset_green); |  | ||||||
|                     furi_record_close("notification"); |  | ||||||
| 
 |  | ||||||
|                     view_port_enabled_set(view_port, false); |  | ||||||
|                     gui_remove_view_port(gui, view_port); |  | ||||||
|                     view_port_free(view_port); |  | ||||||
| 
 |  | ||||||
|                     return 0; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyRight) { |  | ||||||
|                     if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) { |  | ||||||
|                         state->gpio_index++; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|                 if(event.value.input.type == InputTypeShort && |             if(event.key == InputKeyLeft) { | ||||||
|                    event.value.input.key == InputKeyLeft) { |                 if(gpio_test->gpio_index > 0) { | ||||||
|                     if(state->gpio_index > 0) { |                     gpio_test->gpio_index--; | ||||||
|                         state->gpio_index--; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 |         } else { | ||||||
|                 if(event.value.input.key == InputKeyOk) { |             if(event.key == InputKeyOk) { | ||||||
|                     if(event.value.input.type == InputTypePress) { |                 if(event.type == InputTypePress) { | ||||||
|                         hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true); |                     hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, true); | ||||||
|                         notification_message(notification, &sequence_set_green_255); |                     notification_message(gpio_test->notification, &sequence_set_green_255); | ||||||
|                     } else if(event.value.input.type == InputTypeRelease) { |                 } else if(event.type == InputTypeRelease) { | ||||||
|                         hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false); |                     hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, false); | ||||||
|                         notification_message(notification, &sequence_reset_green); |                     notification_message(gpio_test->notification, &sequence_reset_green); | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         release_mutex(&state_mutex, state); |         view_port_update(gpio_test->view_port); | ||||||
|         view_port_update(view_port); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     gpio_test_free(gpio_test); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -309,13 +309,16 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { | |||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|     if(canvas->orientation != orientation) { |     if(canvas->orientation != orientation) { | ||||||
|         canvas->orientation = orientation; |         canvas->orientation = orientation; | ||||||
|         if(canvas->orientation == CanvasOrientationHorizontal) |         if(canvas->orientation == CanvasOrientationHorizontal) { | ||||||
|  |             FURI_SWAP(canvas->width, canvas->height); | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); |             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); | ||||||
|         else if(canvas->orientation == CanvasOrientationVertical) |         } else if(canvas->orientation == CanvasOrientationVertical) { | ||||||
|  |             FURI_SWAP(canvas->width, canvas->height); | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); |             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); | ||||||
|         else |         } else { | ||||||
|             furi_assert(0); |             furi_assert(0); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CanvasOrientation canvas_get_orientation(const Canvas* canvas) { | CanvasOrientation canvas_get_orientation(const Canvas* canvas) { | ||||||
|  | |||||||
| @ -1,40 +1,5 @@ | |||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| 
 | 
 | ||||||
| static void gui_rotate_buttons(InputEvent* event) { |  | ||||||
|     switch(event->key) { |  | ||||||
|     case InputKeyUp: |  | ||||||
|         event->key = InputKeyRight; |  | ||||||
|         break; |  | ||||||
|     case InputKeyDown: |  | ||||||
|         event->key = InputKeyLeft; |  | ||||||
|         break; |  | ||||||
|     case InputKeyRight: |  | ||||||
|         event->key = InputKeyDown; |  | ||||||
|         break; |  | ||||||
|     case InputKeyLeft: |  | ||||||
|         event->key = InputKeyUp; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void gui_setup_fs_orientation(const ViewPort* view_port, Canvas* canvas) { |  | ||||||
|     ViewPortOrientation view_port_orientation = view_port_get_orientation(view_port); |  | ||||||
|     CanvasOrientation canvas_orientation = canvas_get_orientation(canvas); |  | ||||||
|     if(view_port_orientation == ViewPortOrientationHorizontal) { |  | ||||||
|         canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT); |  | ||||||
|         if(canvas_orientation != CanvasOrientationHorizontal) { |  | ||||||
|             canvas_set_orientation(canvas, CanvasOrientationHorizontal); |  | ||||||
|         } |  | ||||||
|     } else if(view_port_orientation == ViewPortOrientationVertical) { |  | ||||||
|         canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_HEIGHT, GUI_DISPLAY_WIDTH); |  | ||||||
|         if(canvas_orientation != CanvasOrientationVertical) { |  | ||||||
|             canvas_set_orientation(canvas, CanvasOrientationVertical); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ||||||
|     // Iterating backward
 |     // Iterating backward
 | ||||||
|     ViewPortArray_it_t it; |     ViewPortArray_it_t it; | ||||||
| @ -66,9 +31,10 @@ void gui_input_events_callback(const void* value, void* ctx) { | |||||||
| 
 | 
 | ||||||
| // Only Fullscreen supports vertical display for now
 | // Only Fullscreen supports vertical display for now
 | ||||||
| bool gui_redraw_fs(Gui* gui) { | bool gui_redraw_fs(Gui* gui) { | ||||||
|  |     canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); | ||||||
|  |     canvas_frame_set(gui->canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT); | ||||||
|     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); |     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); | ||||||
|     if(view_port) { |     if(view_port) { | ||||||
|         gui_setup_fs_orientation(view_port, gui->canvas); |  | ||||||
|         view_port_draw(view_port, gui->canvas); |         view_port_draw(view_port, gui->canvas); | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
| @ -225,9 +191,10 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|     } else if(!(gui->ongoing_input & key_bit)) { |     } else if(!(gui->ongoing_input & key_bit)) { | ||||||
|         FURI_LOG_W( |         FURI_LOG_W( | ||||||
|             "Gui", |             "Gui", | ||||||
|             "non-complementary input, discarding key %s type %s", |             "non-complementary input, discarding key: %s type: %s, sequence: %p", | ||||||
|             input_get_key_name(input_event->key), |             input_get_key_name(input_event->key), | ||||||
|             input_get_type_name(input_event->type)); |             input_get_type_name(input_event->type), | ||||||
|  |             input_event->sequence); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -241,21 +208,27 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|         gui->ongoing_input_view_port = view_port; |         gui->ongoing_input_view_port = view_port; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(view_port) { |     if(view_port && view_port == gui->ongoing_input_view_port) { | ||||||
|         if(view_port == gui->ongoing_input_view_port) { |  | ||||||
|             if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) { |  | ||||||
|                 gui_rotate_buttons(input_event); |  | ||||||
|             } |  | ||||||
|         view_port_input(view_port, input_event); |         view_port_input(view_port, input_event); | ||||||
|         } else { |     } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { | ||||||
|         FURI_LOG_W( |         FURI_LOG_W( | ||||||
|             "Gui", |             "Gui", | ||||||
|                 "ViewPort change while key press %x -> %x. Discarding key: %s, type: %s", |             "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|             gui->ongoing_input_view_port, |             gui->ongoing_input_view_port, | ||||||
|             view_port, |             view_port, | ||||||
|             input_get_key_name(input_event->key), |             input_get_key_name(input_event->key), | ||||||
|                 input_get_type_name(input_event->type)); |             input_get_type_name(input_event->type), | ||||||
|         } |             input_event->sequence); | ||||||
|  |         view_port_input(gui->ongoing_input_view_port, input_event); | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "Gui", | ||||||
|  |             "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", | ||||||
|  |             gui->ongoing_input_view_port, | ||||||
|  |             view_port, | ||||||
|  |             input_get_key_name(input_event->key), | ||||||
|  |             input_get_type_name(input_event->type), | ||||||
|  |             input_event->sequence); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| @ -355,6 +328,10 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(gui->ongoing_input_view_port == view_port) { | ||||||
|  |         gui->ongoing_input_view_port = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) { | |||||||
| void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { | void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { | ||||||
|     furi_assert(view_dispatcher); |     furi_assert(view_dispatcher); | ||||||
|     furi_assert(view_dispatcher->queue == NULL); |     furi_assert(view_dispatcher->queue == NULL); | ||||||
|     view_dispatcher->queue = osMessageQueueNew(8, sizeof(ViewDispatcherMessage), NULL); |     view_dispatcher->queue = osMessageQueueNew(16, sizeof(ViewDispatcherMessage), NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { | void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { | ||||||
| @ -149,6 +149,10 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_ | |||||||
|     if(view_dispatcher->current_view == view) { |     if(view_dispatcher->current_view == view) { | ||||||
|         view_dispatcher_set_current_view(view_dispatcher, NULL); |         view_dispatcher_set_current_view(view_dispatcher, NULL); | ||||||
|     } |     } | ||||||
|  |     // Check if view is recieving input
 | ||||||
|  |     if(view_dispatcher->ongoing_input_view == view) { | ||||||
|  |         view_dispatcher->ongoing_input_view = NULL; | ||||||
|  |     } | ||||||
|     // Remove view
 |     // Remove view
 | ||||||
|     ViewDict_erase(view_dispatcher->views, view_id); |     ViewDict_erase(view_dispatcher->views, view_id); | ||||||
| 
 | 
 | ||||||
| @ -169,13 +173,8 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi | |||||||
|     } else { |     } else { | ||||||
|         View** view_pp = ViewDict_get(view_dispatcher->views, view_id); |         View** view_pp = ViewDict_get(view_dispatcher->views, view_id); | ||||||
|         furi_check(view_pp != NULL); |         furi_check(view_pp != NULL); | ||||||
|         if(view_dispatcher->ongoing_input) { |  | ||||||
|             view_dispatcher->delayed_next_view = *view_pp; |  | ||||||
|         } else { |  | ||||||
|             view_dispatcher->delayed_next_view = NULL; |  | ||||||
|         view_dispatcher_set_current_view(view_dispatcher, *view_pp); |         view_dispatcher_set_current_view(view_dispatcher, *view_pp); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_dispatcher_attach_to_gui( | void view_dispatcher_attach_to_gui( | ||||||
| @ -227,12 +226,20 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e | |||||||
|     } else if(!(view_dispatcher->ongoing_input & key_bit)) { |     } else if(!(view_dispatcher->ongoing_input & key_bit)) { | ||||||
|         FURI_LOG_W( |         FURI_LOG_W( | ||||||
|             "ViewDispatcher", |             "ViewDispatcher", | ||||||
|             "non-complementary input, discarding key: %s, type: %s", |             "non-complementary input, discarding key: %s, type: %s, sequence: %p", | ||||||
|             input_get_key_name(event->key), |             input_get_key_name(event->key), | ||||||
|             input_get_type_name(event->type)); |             input_get_type_name(event->type), | ||||||
|  |             event->sequence); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Set ongoing input view if this is event is first press event
 | ||||||
|  |     if(!(view_dispatcher->ongoing_input & ~key_bit) && event->type == InputTypePress) { | ||||||
|  |         view_dispatcher->ongoing_input_view = view_dispatcher->current_view; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Deliver event
 | ||||||
|  |     if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) { | ||||||
|         bool is_consumed = false; |         bool is_consumed = false; | ||||||
|         if(view_dispatcher->current_view) { |         if(view_dispatcher->current_view) { | ||||||
|             is_consumed = view_input(view_dispatcher->current_view, event); |             is_consumed = view_input(view_dispatcher->current_view, event); | ||||||
| @ -255,11 +262,16 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e | |||||||
|                 view_dispatcher_switch_to_view(view_dispatcher, view_id); |                 view_dispatcher_switch_to_view(view_dispatcher, view_id); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 |     } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { | ||||||
|     // Delayed view switch
 |         FURI_LOG_W( | ||||||
|     if(view_dispatcher->delayed_next_view && !(view_dispatcher->ongoing_input)) { |             "ViewDispatcher", | ||||||
|         view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view); |             "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|         view_dispatcher->delayed_next_view = NULL; |             view_dispatcher->ongoing_input_view, | ||||||
|  |             view_dispatcher->current_view, | ||||||
|  |             input_get_key_name(event->key), | ||||||
|  |             input_get_type_name(event->type), | ||||||
|  |             event->sequence); | ||||||
|  |         view_input(view_dispatcher->ongoing_input_view, event); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ struct ViewDispatcher { | |||||||
| 
 | 
 | ||||||
|     View* current_view; |     View* current_view; | ||||||
| 
 | 
 | ||||||
|     View* delayed_next_view; |     View* ongoing_input_view; | ||||||
|     uint8_t ongoing_input; |     uint8_t ongoing_input; | ||||||
| 
 | 
 | ||||||
|     ViewDispatcherCustomEventCallback custom_event_callback; |     ViewDispatcherCustomEventCallback custom_event_callback; | ||||||
|  | |||||||
| @ -7,6 +7,33 @@ | |||||||
| 
 | 
 | ||||||
| // TODO add mutex to view_port ops
 | // TODO add mutex to view_port ops
 | ||||||
| 
 | 
 | ||||||
|  | static void view_port_rotate_buttons(InputEvent* event) { | ||||||
|  |     switch(event->key) { | ||||||
|  |     case InputKeyUp: | ||||||
|  |         event->key = InputKeyRight; | ||||||
|  |         break; | ||||||
|  |     case InputKeyDown: | ||||||
|  |         event->key = InputKeyLeft; | ||||||
|  |         break; | ||||||
|  |     case InputKeyRight: | ||||||
|  |         event->key = InputKeyDown; | ||||||
|  |         break; | ||||||
|  |     case InputKeyLeft: | ||||||
|  |         event->key = InputKeyUp; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { | ||||||
|  |     if(view_port->orientation == ViewPortOrientationHorizontal) { | ||||||
|  |         canvas_set_orientation(canvas, CanvasOrientationHorizontal); | ||||||
|  |     } else if(view_port->orientation == ViewPortOrientationVertical) { | ||||||
|  |         canvas_set_orientation(canvas, CanvasOrientationVertical); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ViewPort* view_port_alloc() { | ViewPort* view_port_alloc() { | ||||||
|     ViewPort* view_port = furi_alloc(sizeof(ViewPort)); |     ViewPort* view_port = furi_alloc(sizeof(ViewPort)); | ||||||
|     view_port->orientation = ViewPortOrientationHorizontal; |     view_port->orientation = ViewPortOrientationHorizontal; | ||||||
| @ -84,6 +111,7 @@ void view_port_draw(ViewPort* view_port, Canvas* canvas) { | |||||||
|     furi_check(view_port->gui); |     furi_check(view_port->gui); | ||||||
| 
 | 
 | ||||||
|     if(view_port->draw_callback) { |     if(view_port->draw_callback) { | ||||||
|  |         view_port_setup_canvas_orientation(view_port, canvas); | ||||||
|         view_port->draw_callback(canvas, view_port->draw_callback_context); |         view_port->draw_callback(canvas, view_port->draw_callback_context); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -94,6 +122,9 @@ void view_port_input(ViewPort* view_port, InputEvent* event) { | |||||||
|     furi_check(view_port->gui); |     furi_check(view_port->gui); | ||||||
| 
 | 
 | ||||||
|     if(view_port->input_callback) { |     if(view_port->input_callback) { | ||||||
|  |         if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) { | ||||||
|  |             view_port_rotate_buttons(event); | ||||||
|  |         } | ||||||
|         view_port->input_callback(event, view_port->input_callback_context); |         view_port->input_callback(event, view_port->input_callback_context); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ inline static void input_timer_stop(osTimerId_t timer_id) { | |||||||
| void input_press_timer_callback(void* arg) { | void input_press_timer_callback(void* arg) { | ||||||
|     InputPinState* input_pin = arg; |     InputPinState* input_pin = arg; | ||||||
|     InputEvent event; |     InputEvent event; | ||||||
|  |     event.sequence = input_pin->counter; | ||||||
|     event.key = input_pin->pin->key; |     event.key = input_pin->pin->key; | ||||||
|     input_pin->press_counter++; |     input_pin->press_counter++; | ||||||
|     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { |     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { | ||||||
| @ -158,8 +159,12 @@ int32_t input_srv() { | |||||||
| 
 | 
 | ||||||
|                 // Short / Long / Repeat timer routine
 |                 // Short / Long / Repeat timer routine
 | ||||||
|                 if(state) { |                 if(state) { | ||||||
|  |                     input->counter++; | ||||||
|  |                     input->pin_states[i].counter = input->counter; | ||||||
|  |                     event.sequence = input->pin_states[i].counter; | ||||||
|                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); |                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); | ||||||
|                 } else { |                 } else { | ||||||
|  |                     event.sequence = input->pin_states[i].counter; | ||||||
|                     input_timer_stop(input->pin_states[i].press_timer); |                     input_timer_stop(input->pin_states[i].press_timer); | ||||||
|                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { |                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { | ||||||
|                         event.type = InputTypeShort; |                         event.type = InputTypeShort; | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| /* Input Event, dispatches with PubSub */ | /* Input Event, dispatches with PubSub */ | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     uint32_t sequence; | ||||||
|     InputKey key; |     InputKey key; | ||||||
|     InputType type; |     InputType type; | ||||||
| } InputEvent; | } InputEvent; | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ typedef struct { | |||||||
|     volatile uint8_t debounce; |     volatile uint8_t debounce; | ||||||
|     volatile osTimerId_t press_timer; |     volatile osTimerId_t press_timer; | ||||||
|     volatile uint8_t press_counter; |     volatile uint8_t press_counter; | ||||||
|  |     volatile uint32_t counter; | ||||||
| } InputPinState; | } InputPinState; | ||||||
| 
 | 
 | ||||||
| /* Input state */ | /* Input state */ | ||||||
| @ -32,6 +33,7 @@ typedef struct { | |||||||
|     PubSub event_pubsub; |     PubSub event_pubsub; | ||||||
|     InputPinState* pin_states; |     InputPinState* pin_states; | ||||||
|     Cli* cli; |     Cli* cli; | ||||||
|  |     volatile uint32_t counter; | ||||||
| } Input; | } Input; | ||||||
| 
 | 
 | ||||||
| /* Input press timer callback */ | /* Input press timer callback */ | ||||||
|  | |||||||
| @ -383,11 +383,6 @@ int32_t music_player_app(void* p) { | |||||||
|     Gui* gui = furi_record_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // open input record
 |  | ||||||
|     PubSub* input_events_record = furi_record_open("input_events"); |  | ||||||
|     // prepare "do nothing" event
 |  | ||||||
|     InputEvent input_event = {InputKeyRight, true}; |  | ||||||
| 
 |  | ||||||
|     // start player thread
 |     // start player thread
 | ||||||
|     // TODO change to fuirac_start
 |     // TODO change to fuirac_start
 | ||||||
|     osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512}; |     osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512}; | ||||||
| @ -410,14 +405,8 @@ int32_t music_player_app(void* p) { | |||||||
|                 // press events
 |                 // press events
 | ||||||
|                 if(event.value.input.type == InputTypeShort && |                 if(event.value.input.type == InputTypeShort && | ||||||
|                    event.value.input.key == InputKeyBack) { |                    event.value.input.key == InputKeyBack) { | ||||||
|                     osThreadTerminate(player); |                     release_mutex(&state_mutex, state); | ||||||
|                     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); |                     break; | ||||||
|                     view_port_enabled_set(view_port, false); |  | ||||||
|                     gui_remove_view_port(gui, view_port); |  | ||||||
|                     view_port_free(view_port); |  | ||||||
|                     osMessageQueueDelete(event_queue); |  | ||||||
| 
 |  | ||||||
|                     return 0; |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if(event.value.input.type == InputTypePress && |                 if(event.value.input.type == InputTypePress && | ||||||
| @ -442,9 +431,6 @@ int32_t music_player_app(void* p) { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             } else if(event.type == EventTypeNote) { |             } else if(event.type == EventTypeNote) { | ||||||
|                 // send "do nothing" event to prevent display backlight off
 |  | ||||||
|                 notify_pubsub(input_events_record, &input_event); |  | ||||||
| 
 |  | ||||||
|                 state->note_record = event.value.note_record; |                 state->note_record = event.value.note_record; | ||||||
| 
 | 
 | ||||||
|                 for(size_t i = note_stack_size - 1; i > 0; i--) { |                 for(size_t i = note_stack_size - 1; i > 0; i--) { | ||||||
| @ -460,5 +446,14 @@ int32_t music_player_app(void* p) { | |||||||
|         release_mutex(&state_mutex, state); |         release_mutex(&state_mutex, state); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     osThreadTerminate(player); | ||||||
|  |     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); | ||||||
|  |     view_port_enabled_set(view_port, false); | ||||||
|  |     gui_remove_view_port(gui, view_port); | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     view_port_free(view_port); | ||||||
|  |     osMessageQueueDelete(event_queue); | ||||||
|  |     delete_mutex(&state_mutex); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ ADD_SCENE(subghz, save_name, SaveName) | |||||||
| ADD_SCENE(subghz, save_success, SaveSuccess) | ADD_SCENE(subghz, save_success, SaveSuccess) | ||||||
| ADD_SCENE(subghz, saved, Saved) | ADD_SCENE(subghz, saved, Saved) | ||||||
| ADD_SCENE(subghz, transmitter, Transmitter) | ADD_SCENE(subghz, transmitter, Transmitter) | ||||||
|  | ADD_SCENE(subghz, no_man, NoMan) | ||||||
| ADD_SCENE(subghz, test, Test) | ADD_SCENE(subghz, test, Test) | ||||||
| ADD_SCENE(subghz, test_static, TestStatic) | ADD_SCENE(subghz, test_static, TestStatic) | ||||||
| ADD_SCENE(subghz, test_carrier, TestCarrier) | ADD_SCENE(subghz, test_carrier, TestCarrier) | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								applications/subghz/scenes/subghz_scene_no_man.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								applications/subghz/scenes/subghz_scene_no_man.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | #include "../subghz_i.h" | ||||||
|  | 
 | ||||||
|  | #define SCENE_NO_MAN_CUSTOM_EVENT (11UL) | ||||||
|  | 
 | ||||||
|  | void subghz_scene_no_man_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) { | ||||||
|  |     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_timeout(popup, 1500); | ||||||
|  |     popup_set_context(popup, subghz); | ||||||
|  |     popup_set_callback(popup, subghz_scene_no_man_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) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { | ||||||
|  |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_no_man_on_exit(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     Popup* popup = subghz->popup; | ||||||
|  |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||||
|  |     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||||
|  |     popup_set_icon(popup, 0, 0, NULL); | ||||||
|  |     popup_set_callback(popup, NULL); | ||||||
|  |     popup_set_context(popup, NULL); | ||||||
|  |     popup_set_timeout(popup, 0); | ||||||
|  |     popup_disable_timeout(popup); | ||||||
|  | } | ||||||
| @ -57,6 +57,10 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event | |||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|  |         case SubghzReceverEventSendHistoryFull: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -146,11 +146,15 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event | |||||||
|                 subghz->protocol_result->serial = key & 0x0FFFFFFF; |                 subghz->protocol_result->serial = key & 0x0FFFFFFF; | ||||||
|                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 |                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->cnt = 0x0003; |                 subghz->protocol_result->cnt = 0x0003; | ||||||
|                 subghz_protocol_keeloq_set_manufacture_name(subghz->protocol_result, "DoorHan"); |                 if(subghz_protocol_keeloq_set_manufacture_name( | ||||||
|  |                        subghz->protocol_result, "DoorHan")) { | ||||||
|                     subghz->protocol_result->code_last_found = |                     subghz->protocol_result->code_last_found = | ||||||
|                         subghz_protocol_keeloq_gen_key(subghz->protocol_result); |                         subghz_protocol_keeloq_gen_key(subghz->protocol_result); | ||||||
| 
 |  | ||||||
|                     generated_protocol = true; |                     generated_protocol = true; | ||||||
|  |                 } else { | ||||||
|  |                     generated_protocol = false; | ||||||
|  |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,6 +38,11 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev | |||||||
|             scene_manager_search_and_switch_to_previous_scene( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart); |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|             return true; |             return true; | ||||||
|  |         } else if(event.event == SubghzTransmitterEventNoMan) { | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneNoMan); | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { |         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { | ||||||
|  | |||||||
| @ -129,8 +129,8 @@ SubGhz* subghz_alloc() { | |||||||
|         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); |         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); | ||||||
|     subghz_worker_set_context(subghz->worker, subghz->protocol); |     subghz_worker_set_context(subghz->worker, subghz->protocol); | ||||||
| 
 | 
 | ||||||
|     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes"); |     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes"); | ||||||
|     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx"); |     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx"); | ||||||
| 
 | 
 | ||||||
|     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 |     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -206,8 +206,8 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { | |||||||
|     furi_check(instance->stream); |     furi_check(instance->stream); | ||||||
| 
 | 
 | ||||||
|     SubGhzProtocol* protocol = subghz_protocol_alloc(); |     SubGhzProtocol* protocol = subghz_protocol_alloc(); | ||||||
|     subghz_protocol_load_keeloq_file(protocol, "/ext/assets/subghz/keeloq_mfcodes"); |     subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes"); | ||||||
|     subghz_protocol_load_nice_flor_s_file(protocol, "/ext/assets/subghz/nice_floor_s_rx"); |     subghz_protocol_load_nice_flor_s_file(protocol, "/ext/subghz/nice_floor_s_rx"); | ||||||
|     subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance); |     subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance); | ||||||
| 
 | 
 | ||||||
|     // Configure radio
 |     // Configure radio
 | ||||||
|  | |||||||
| @ -88,9 +88,15 @@ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, u | |||||||
|     instance->data.param1 = instance->history[idx].te; |     instance->data.param1 = instance->history[idx].te; | ||||||
|     return &instance->data; |     return &instance->data; | ||||||
| } | } | ||||||
| void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { | bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|  |     if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { | ||||||
|  |         if(output != NULL) string_printf(output, "Memory is FULL"); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     if(output != NULL) | ||||||
|         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); |         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); | ||||||
|  |     return false; | ||||||
| } | } | ||||||
| void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) { | void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) { | ||||||
|     if(instance->history[idx].code_count_bit < 33) { |     if(instance->history[idx].code_count_bit < 33) { | ||||||
| @ -144,10 +150,10 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { | |||||||
|     instance->history[instance->last_index_write].code_found = protocol->code_last_found; |     instance->history[instance->last_index_write].code_found = protocol->code_last_found; | ||||||
|     if(strcmp(protocol->name, "KeeLoq") == 0) { |     if(strcmp(protocol->name, "KeeLoq") == 0) { | ||||||
|         instance->history[instance->last_index_write].manufacture_name = |         instance->history[instance->last_index_write].manufacture_name = | ||||||
|             subghz_protocol_keeloq_get_manufacture_name(protocol); |             subghz_protocol_keeloq_find_and_get_manufacture_name(protocol); | ||||||
|     } else if(strcmp(protocol->name, "Star Line") == 0) { |     } else if(strcmp(protocol->name, "Star Line") == 0) { | ||||||
|         instance->history[instance->last_index_write].manufacture_name = |         instance->history[instance->last_index_write].manufacture_name = | ||||||
|             subghz_protocol_star_line_get_manufacture_name(protocol); |             subghz_protocol_star_line_find_and_get_manufacture_name(protocol); | ||||||
|     } else if(strcmp(protocol->name, "Princeton") == 0) { |     } else if(strcmp(protocol->name, "Princeton") == 0) { | ||||||
|         instance->history[instance->last_index_write].te = |         instance->history[instance->last_index_write].te = | ||||||
|             subghz_protocol_princeton_get_te(protocol); |             subghz_protocol_princeton_get_te(protocol); | ||||||
|  | |||||||
| @ -4,20 +4,103 @@ | |||||||
| 
 | 
 | ||||||
| typedef struct SubGhzHistory SubGhzHistory; | typedef struct SubGhzHistory SubGhzHistory; | ||||||
| 
 | 
 | ||||||
|  | /** Allocate SubGhzHistory
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzHistory*  | ||||||
|  |  */ | ||||||
| SubGhzHistory* subghz_history_alloc(void); | SubGhzHistory* subghz_history_alloc(void); | ||||||
|  | 
 | ||||||
|  | /** Free SubGhzHistory
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzHistory instance | ||||||
|  |  */ | ||||||
| void subghz_history_free(SubGhzHistory* instance); | void subghz_history_free(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Clear history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzHistory instance | ||||||
|  |  */ | ||||||
| void subghz_history_clean(SubGhzHistory* instance); | void subghz_history_clean(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Set frequency and preset to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @param frequency - frequency Hz | ||||||
|  |  * @param preset    - FuriHalSubGhzPreset preset | ||||||
|  |  */ | ||||||
| void subghz_history_set_frequency_preset( | void subghz_history_set_frequency_preset( | ||||||
|     SubGhzHistory* instance, |     SubGhzHistory* instance, | ||||||
|     uint16_t idx, |     uint16_t idx, | ||||||
|     uint32_t frequency, |     uint32_t frequency, | ||||||
|     FuriHalSubGhzPreset preset); |     FuriHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | /** Get frequency to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return frequency - frequency Hz | ||||||
|  |  */ | ||||||
| uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx); | uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get preset to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return preset    - FuriHalSubGhzPreset preset | ||||||
|  |  */ | ||||||
| FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx); | FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get history index write 
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @return idx      - current record index   | ||||||
|  |  */ | ||||||
| uint16_t subghz_history_get_item(SubGhzHistory* instance); | uint16_t subghz_history_get_item(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Get type protocol to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return type      - type protocol   | ||||||
|  |  */ | ||||||
| uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx); | uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get name protocol to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return name      - const char* name protocol   | ||||||
|  |  */ | ||||||
| const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx); | const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get string item menu to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param output    - string_t output | ||||||
|  |  * @param idx       - record index | ||||||
|  |  */ | ||||||
| void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx); | void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx); | ||||||
| void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output); | 
 | ||||||
|  | /** Get string the remaining number of records to history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param output    - string_t output | ||||||
|  |  * @return bool - is FUUL | ||||||
|  |  */ | ||||||
|  | bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Add protocol to history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param context    - SubGhzProtocolCommon context | ||||||
|  |  */ | ||||||
| void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | ||||||
|  | 
 | ||||||
|  | /** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index | ||||||
|  |  * @return SubGhzProtocolCommonLoad* | ||||||
|  |  */ | ||||||
| SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | |||||||
| @ -39,9 +39,9 @@ typedef enum { | |||||||
| } SubGhzHopperState; | } SubGhzHopperState; | ||||||
| 
 | 
 | ||||||
| static const Icon* ReceiverItemIcons[] = { | static const Icon* ReceiverItemIcons[] = { | ||||||
|     [TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8, |     [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, | ||||||
|     [TYPE_PROTOCOL_STATIC] = &I_unlock_7x8, |     [TYPE_PROTOCOL_STATIC] = &I_Unlock_7x8, | ||||||
|     [TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8, |     [TYPE_PROTOCOL_DYNAMIC] = &I_Lock_7x8, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct SubghzReceiver { | struct SubghzReceiver { | ||||||
| @ -53,6 +53,7 @@ struct SubghzReceiver { | |||||||
|     osTimerId timer; |     osTimerId timer; | ||||||
|     SubGhzHopperState hopper_state; |     SubGhzHopperState hopper_state; | ||||||
|     uint8_t hopper_timeout; |     uint8_t hopper_timeout; | ||||||
|  |     uint32_t event_key_sequence; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -172,12 +173,16 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|             string_clean(str_buff); |             string_clean(str_buff); | ||||||
|         } |         } | ||||||
|         if(scrollbar) { |         if(scrollbar) { | ||||||
|             elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item); |             elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); | ||||||
|         } |         } | ||||||
|         canvas_set_color(canvas, ColorBlack); |         canvas_set_color(canvas, ColorBlack); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
| 
 | 
 | ||||||
|         elements_button_left(canvas, "Conf"); |         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) { |             if((model->real_frequency / 1000 % 10) > 4) { | ||||||
|                 frequency = model->real_frequency + 10000; |                 frequency = model->real_frequency + 10000; | ||||||
|             } else { |             } else { | ||||||
| @ -189,27 +194,19 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|                 "%03ld.%02ld", |                 "%03ld.%02ld", | ||||||
|                 frequency / 1000000 % 1000, |                 frequency / 1000000 % 1000, | ||||||
|                 frequency / 10000 % 100); |                 frequency / 10000 % 100); | ||||||
|         canvas_draw_str(canvas, 40, 62, buffer); |             canvas_draw_str(canvas, 44, 62, buffer); | ||||||
|         canvas_draw_str(canvas, 75, 62, "AM"); |             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_str(canvas, 94, 62, string_get_cstr(str_buff)); |         } | ||||||
|         canvas_draw_line(canvas, 38, 51, 125, 51); |  | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case ReceiverSceneStart: |     case ReceiverSceneStart: | ||||||
|         canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61); |         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         canvas_draw_box(canvas, 80, 2, 20, 20); |  | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         canvas_draw_icon(canvas, 75, 8, &I_sub1_10px); |  | ||||||
|         canvas_set_font(canvas, FontPrimary); |         canvas_set_font(canvas, FontPrimary); | ||||||
|         canvas_draw_str(canvas, 63, 40, "Scanning..."); |         canvas_draw_str(canvas, 63, 46, "Scanning..."); | ||||||
|         canvas_set_color(canvas, ColorBlack); |         canvas_set_color(canvas, ColorBlack); | ||||||
|         canvas_set_font(canvas, FontSecondary); |         canvas_set_font(canvas, FontSecondary); | ||||||
|         elements_button_left(canvas, "Conf"); |         elements_button_left(canvas, "Config"); | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         canvas_draw_box(canvas, 38, 52, 10, 10); |  | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         if((model->real_frequency / 1000 % 10) > 4) { |         if((model->real_frequency / 1000 % 10) > 4) { | ||||||
|             frequency = model->real_frequency + 10000; |             frequency = model->real_frequency + 10000; | ||||||
|         } else { |         } else { | ||||||
| @ -221,11 +218,11 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|             "%03ld.%02ld", |             "%03ld.%02ld", | ||||||
|             frequency / 1000000 % 1000, |             frequency / 1000000 % 1000, | ||||||
|             frequency / 10000 % 100); |             frequency / 10000 % 100); | ||||||
|         canvas_draw_str(canvas, 40, 62, buffer); |         canvas_draw_str(canvas, 44, 62, buffer); | ||||||
|         canvas_draw_str(canvas, 75, 62, "AM"); |         canvas_draw_str(canvas, 79, 62, "AM"); | ||||||
|         subghz_history_get_text_space_left(model->history, str_buff); |         subghz_history_get_text_space_left(model->history, str_buff); | ||||||
|         canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff)); |         canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); | ||||||
|         canvas_draw_line(canvas, 48, 51, 125, 51); |         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case ReceiverSceneConfig: |     case ReceiverSceneConfig: | ||||||
| @ -237,9 +234,12 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|                 model->real_frequency / 1000000 % 1000, |                 model->real_frequency / 1000000 % 1000, | ||||||
|                 model->real_frequency / 1000 % 1000); |                 model->real_frequency / 1000 % 1000); | ||||||
|             canvas_draw_str(canvas, 0, 8, buffer); |             canvas_draw_str(canvas, 0, 8, buffer); | ||||||
|  |             canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>"); | ||||||
|         } else { |         } else { | ||||||
|             canvas_draw_str(canvas, 0, 8, "Frequency: <auto>"); |             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"); |         elements_button_center(canvas, "Save"); | ||||||
|         break; |         break; | ||||||
| @ -269,6 +269,13 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|     string_clear(str_buff); |     string_clear(str_buff); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void subghz_receiver_history_full(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzReceiver* subghz_receiver = context; | ||||||
|  |     subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context); | ||||||
|  |     subghz_receiver->hopper_state = SubGhzHopperStateOFF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool subghz_receiver_input(InputEvent* event, void* context) { | bool subghz_receiver_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| 
 | 
 | ||||||
| @ -280,13 +287,11 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false; |  | ||||||
| 
 |  | ||||||
|     bool can_be_saved = false; |     bool can_be_saved = false; | ||||||
| 
 | 
 | ||||||
|     switch(scene) { |     switch(scene) { | ||||||
|     case ReceiverSceneMain: |     case ReceiverSceneMain: | ||||||
|         if(event->key == InputKeyBack) { |         if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                     model->idx = 0; |                     model->idx = 0; | ||||||
| @ -296,19 +301,23 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
|             return false; |             return false; | ||||||
|         } else if(event->key == InputKeyUp) { |         } else if( | ||||||
|  |             event->key == InputKeyUp && | ||||||
|  |             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                     if(model->idx != 0) model->idx--; |                     if(model->idx != 0) model->idx--; | ||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
|         } else if(event->key == InputKeyDown) { |         } else if( | ||||||
|  |             event->key == InputKeyDown && | ||||||
|  |             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                     if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++; |                     if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++; | ||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
|         } else if(event->key == InputKeyLeft) { |         } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|             subghz_receiver->hopper_state = SubGhzHopperStatePause; |             subghz_receiver->hopper_state = SubGhzHopperStatePause; | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
| @ -317,7 +326,8 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
|             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); |             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); | ||||||
|         } else if(event->key == InputKeyOk) { |         } else if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|  |             subghz_receiver->event_key_sequence = event->sequence; | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|                     string_clean(model->text); |                     string_clean(model->text); | ||||||
| @ -358,18 +368,23 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|         } else if(can_be_saved && event->key == InputKeyRight) { |         } else if(can_be_saved && event->key == InputKeyRight) { | ||||||
|             subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); |             subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); | ||||||
|             return false; |             return false; | ||||||
|         } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypePress) { |         } else if( | ||||||
|  |             can_be_saved && event->key == InputKeyOk && event->type == InputTypePress && | ||||||
|  |             subghz_receiver->event_key_sequence != event->sequence) { | ||||||
|             subghz_receiver->hopper_state = SubGhzHopperStatePause; |             subghz_receiver->hopper_state = SubGhzHopperStatePause; | ||||||
|             subghz_rx_end(subghz_receiver->worker); |             subghz_rx_end(subghz_receiver->worker); | ||||||
|             subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context); |             subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context); | ||||||
|             return true; |             return true; | ||||||
|         } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease) { |         } 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); |             subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case ReceiverSceneConfig: |     case ReceiverSceneConfig: | ||||||
|  |         if(event->type != InputTypeShort) return false; | ||||||
|         if(event->key == InputKeyBack) { |         if(event->key == InputKeyBack) { | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 subghz_receiver->view, (SubghzReceiverModel * model) { |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
| @ -396,7 +411,6 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|                         osTimerStart(subghz_receiver->timer, 1024 / 10); |                         osTimerStart(subghz_receiver->timer, 1024 / 10); | ||||||
|                         subghz_receiver->hopper_state = SubGhzHopperStateRunnig; |                         subghz_receiver->hopper_state = SubGhzHopperStateRunnig; | ||||||
|                     } |                     } | ||||||
| 
 |  | ||||||
|                     if(subghz_history_get_item(model->history) == 0) { |                     if(subghz_history_get_item(model->history) == 0) { | ||||||
|                         model->scene = ReceiverSceneStart; |                         model->scene = ReceiverSceneStart; | ||||||
|                     } else { |                     } else { | ||||||
| @ -426,6 +440,7 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case ReceiverSceneStart: |     case ReceiverSceneStart: | ||||||
|  |         if(event->type != InputTypeShort) return false; | ||||||
|         if(event->key == InputKeyBack) { |         if(event->key == InputKeyBack) { | ||||||
|             return false; |             return false; | ||||||
|         } else if(event->key == InputKeyLeft) { |         } else if(event->key == InputKeyLeft) { | ||||||
| @ -445,6 +460,16 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |     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; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -476,6 +501,9 @@ void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* conte | |||||||
| 
 | 
 | ||||||
|             model->history_item = subghz_history_get_item(model->history); |             model->history_item = subghz_history_get_item(model->history); | ||||||
|             model->scene = ReceiverSceneMain; |             model->scene = ReceiverSceneMain; | ||||||
|  |             if(subghz_history_get_text_space_left(model->history, NULL)) { | ||||||
|  |                 subghz_receiver_history_full(subghz_receiver); | ||||||
|  |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     subghz_protocol_reset(subghz_receiver->protocol); |     subghz_protocol_reset(subghz_receiver->protocol); | ||||||
| @ -528,10 +556,11 @@ static void subghz_receiver_timer_callback(void* context) { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // Restart radio
 |             // Restart radio
 | ||||||
|             subghz_rx_end(subghz_receiver->worker); |             furi_hal_subghz_idle(); | ||||||
|             subghz_protocol_reset(subghz_receiver->protocol); |             subghz_protocol_reset(subghz_receiver->protocol); | ||||||
|             model->real_frequency = |             model->real_frequency = furi_hal_subghz_set_frequency_and_path( | ||||||
|                 subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]); |                 subghz_frequencies_hopper[model->frequency]); | ||||||
|  |             furi_hal_subghz_rx(); | ||||||
| 
 | 
 | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -14,7 +14,8 @@ typedef enum { | |||||||
|     SubghzReceverEventBack, |     SubghzReceverEventBack, | ||||||
|     SubghzReceverEventMore, |     SubghzReceverEventMore, | ||||||
|     SubghzReceverEventSendStart, |     SubghzReceverEventSendStart, | ||||||
|     SubghzReceverEventSendStop |     SubghzReceverEventSendStop, | ||||||
|  |     SubghzReceverEventSendHistoryFull, | ||||||
| } SubghzReceverEvent; | } SubghzReceverEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzReceiver SubghzReceiver; | typedef struct SubghzReceiver SubghzReceiver; | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||||
| 
 | 
 | ||||||
| struct SubghzTransmitter { | struct SubghzTransmitter { | ||||||
|     View* view; |     View* view; | ||||||
| @ -100,6 +101,10 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | |||||||
|     canvas_draw_str(canvas, 90, 8, buffer); |     canvas_draw_str(canvas, 90, 8, buffer); | ||||||
| 
 | 
 | ||||||
|     if(model->protocol && model->protocol->get_upload_protocol) { |     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"); |         subghz_transmitter_button_right(canvas, "Send"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -107,22 +112,33 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | |||||||
| bool subghz_transmitter_input(InputEvent* event, void* context) { | bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubghzTransmitter* subghz_transmitter = context; | ||||||
|     bool can_be_send = false; |     bool can_be_sent = false; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             can_be_send = (model->protocol && model->protocol->get_upload_protocol); |             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; | ||||||
|  |                 } | ||||||
|  |                 can_be_sent = true; | ||||||
|  |             } | ||||||
|  |             //can_be_sent = (model->protocol && model->protocol->get_upload_protocol);
 | ||||||
|             string_clean(model->text); |             string_clean(model->text); | ||||||
|             model->protocol->to_string(model->protocol, model->text); |             model->protocol->to_string(model->protocol, model->text); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     //if(event->type != InputTypeShort) return false;
 |     //if(event->type != InputTypeShort) return false;
 | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { | ||||||
|         return false; |  | ||||||
|     } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypePress) { |  | ||||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); |         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypeRelease) { |     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { | ||||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context); |         subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -147,6 +163,7 @@ void subghz_transmitter_enter(void* context) { | |||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubghzTransmitter* subghz_transmitter = context; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|  |             string_clean(model->text); | ||||||
|             model->protocol->to_string(model->protocol, model->text); |             model->protocol->to_string(model->protocol, model->text); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ typedef enum { | |||||||
|     SubghzTransmitterEventSendStart, |     SubghzTransmitterEventSendStart, | ||||||
|     SubghzTransmitterEventSendStop, |     SubghzTransmitterEventSendStop, | ||||||
|     SubghzTransmitterEventBack, |     SubghzTransmitterEventBack, | ||||||
|  |     SubghzTransmitterEventNoMan, | ||||||
| } SubghzTransmitterEvent; | } SubghzTransmitterEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzTransmitter SubghzTransmitter; | typedef struct SubghzTransmitter SubghzTransmitter; | ||||||
|  | |||||||
| @ -98,23 +98,17 @@ const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0}; | |||||||
| const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,}; | const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,}; | ||||||
| const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; | const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; | const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||||
| const uint8_t *_I_quest_7x8[] = {_I_quest_7x8_0}; | const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; | const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; | ||||||
| const uint8_t *_I_unlock_7x8[] = {_I_unlock_7x8_0}; | const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_Scanning_dolph_67_61_0[] = {0x00,0x00,0xFE,0x1F,0x00,0x00,0x20,0x00,0x00,0x00,0xC0,0x01,0xE0,0x01,0x00,0x10,0x00,0x00,0x00,0x30,0x00,0x00,0x06,0x00,0x10,0x00,0x00,0x00,0x0C,0x00,0x00,0x18,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x00,0x08,0x08,0x00,0x00,0x01,0x00,0x00,0x40,0x00,0x04,0x04,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x04,0x04,0x00,0x40,0x00,0x00,0x00,0x00,0x01,0x04,0x02,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x00,0x20,0x00,0x00,0x00,0x3C,0x04,0x02,0x81,0x00,0x10,0x00,0x00,0x00,0x42,0x04,0x02,0x41,0x00,0x10,0x00,0x00,0x00,0x81,0x08,0x02,0x41,0x00,0x08,0x06,0x00,0x80,0x18,0x09,0x02,0x41,0x00,0x08,0x09,0x08,0x80,0x24,0x09,0x02,0x41,0x00,0x84,0x10,0x08,0x80,0x24,0x11,0x02,0x41,0x00,0xC4,0x10,0x10,0x80,0x24,0x11,0x02,0x81,0x00,0x44,0x10,0x10,0x80,0x24,0x11,0x02,0x02,0x00,0x46,0x20,0x20,0x80,0x24,0x11,0x04,0x02,0x00,0x2A,0x20,0x20,0x80,0x24,0x11,0x04,0x04,0x00,0x36,0x20,0x40,0x80,0x18,0x11,0x04,0x04,0x00,0x1B,0xE0,0x80,0x00,0x81,0x10,0x08,0x08,0x00,0x0D,0xE0,0x00,0x01,0x42,0x10,0x08,0x00,0x00,0x07,0xE0,0x01,0x00,0x3C,0x18,0x10,0x00,0x00,0x03,0xF0,0x01,0x00,0x00,0x14,0x10,0x00,0x00,0x01,0xF0,0x03,0x00,0x00,0x0A,0x20,0x00,0x00,0x00,0xD0,0xFF,0x01,0x00,0x08,0x00,0x00,0x00,0x00,0xD0,0xFF,0x01,0x00,0x0C,0x00,0x00,0x00,0x00,0x18,0xFF,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x08,0x3C,0x00,0x1F,0x0E,0x00,0x00,0x00,0x00,0x18,0x00,0x60,0x80,0x06,0x00,0x00,0x00,0x00,0x0C,0x00,0x08,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x00,0x02,0x00,0x07,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x80,0x05,0x18,0x00,0x00,0x10,0x00,0x00,0x00,0xC0,0x02,0x20,0x00,0x00,0x10,0x00,0x00,0x00,0x40,0x05,0xC0,0x00,0x00,0x20,0x00,0x00,0x00,0xA0,0x02,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x50,0x01,0x00,0x06,0x00,0x40,0x00,0x00,0x00,0xB0,0x00,0x14,0x08,0x00,0x40,0x00,0x00,0x00,0x58,0x00,0x6A,0x30,0x00,0x40,0x00,0x00,0x00,0xAC,0x00,0xD4,0x41,0x00,0x40,0x00,0x00,0x00,0x54,0x00,0xA8,0x83,0x01,0x40,0x00,0x00,0x00,0x2A,0x00,0x50,0x0F,0x02,0x40,0x00,0x00,0x00,0x15,0x00,0xA0,0x1E,0xFC,0x5F,0x00,0x00,0x00,0x0B,0x00,0x40,0x7D,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0xA0,0xFA,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,}; | const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; | ||||||
| const uint8_t *_I_Scanning_dolph_67_61[] = {_I_Scanning_dolph_67_61_0}; | const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_Broadcast_dolph_67_61_0[] = {0x00,0x00,0xFE,0x1F,0x00,0x00,0x00,0x40,0x00,0x00,0xC0,0x01,0xE0,0x01,0x00,0x00,0x80,0x00,0x00,0x30,0x00,0x00,0x06,0x00,0x00,0x80,0x00,0x00,0x0C,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x20,0x00,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x40,0x00,0x00,0x02,0x02,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x02,0x02,0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x04,0x02,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x04,0x20,0x00,0x00,0x00,0x3C,0x04,0x10,0x08,0x04,0x10,0x00,0x00,0x00,0x42,0x04,0x20,0x08,0x04,0x10,0x00,0x00,0x00,0x81,0x08,0x20,0x08,0x04,0x08,0x06,0x00,0x80,0x18,0x09,0x20,0x08,0x04,0x08,0x09,0x08,0x80,0x24,0x09,0x20,0x08,0x04,0x84,0x10,0x08,0x80,0x24,0x11,0x20,0x08,0x04,0xC4,0x10,0x10,0x80,0x24,0x11,0x10,0x08,0x04,0x44,0x10,0x10,0x80,0x24,0x11,0x00,0x04,0x04,0x46,0x20,0x20,0x80,0x24,0x11,0x00,0x04,0x02,0x2A,0x20,0x20,0x80,0x24,0x11,0x00,0x02,0x02,0x36,0x20,0x40,0x80,0x18,0x11,0x00,0x02,0x02,0x1B,0xE0,0x80,0x00,0x81,0x10,0x00,0x01,0x01,0x0D,0xE0,0x00,0x01,0x42,0x10,0x00,0x00,0x01,0x07,0xE0,0x01,0x00,0x3C,0x18,0x00,0x80,0x00,0x03,0xF0,0x01,0x00,0x00,0x14,0x00,0x80,0x00,0x01,0xF0,0x03,0x00,0x00,0x0A,0x00,0x40,0x00,0x00,0xD0,0xFF,0x01,0x00,0x08,0x00,0x00,0x00,0x00,0xD0,0xFF,0x01,0x00,0x0C,0x00,0x00,0x00,0x00,0x18,0xFF,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x08,0x3C,0x00,0x1F,0x0E,0x00,0x00,0x00,0x00,0x18,0x00,0x60,0x80,0x06,0x00,0x00,0x00,0x00,0x0C,0x00,0x08,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x00,0x02,0x00,0x07,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x80,0x05,0x18,0x00,0x00,0x10,0x00,0x00,0x00,0xC0,0x02,0x20,0x00,0x00,0x10,0x00,0x00,0x00,0x40,0x05,0xC0,0x00,0x00,0x20,0x00,0x00,0x00,0xA0,0x02,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x50,0x01,0x00,0x06,0x00,0x40,0x00,0x00,0x00,0xB0,0x00,0x14,0x08,0x00,0x40,0x00,0x00,0x00,0x58,0x00,0x6A,0x30,0x00,0x40,0x00,0x00,0x00,0xAC,0x00,0xD4,0x41,0x00,0x40,0x00,0x00,0x00,0x54,0x00,0xA8,0x83,0x01,0x40,0x00,0x00,0x00,0x2A,0x00,0x50,0x0F,0x02,0x40,0x00,0x00,0x00,0x15,0x00,0xA0,0x1E,0xFC,0x5F,0x00,0x00,0x00,0x0B,0x00,0x40,0x7D,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0xA0,0xFA,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,}; | const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; | ||||||
| const uint8_t *_I_Broadcast_dolph_67_61[] = {_I_Broadcast_dolph_67_61_0}; | const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; | ||||||
| 
 |  | ||||||
| const uint8_t _I_lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; |  | ||||||
| const uint8_t *_I_lock_7x8[] = {_I_lock_7x8_0}; |  | ||||||
| 
 |  | ||||||
| const uint8_t _I_Top_frame_128_13_0[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,}; |  | ||||||
| const uint8_t *_I_Top_frame_128_13[] = {_I_Top_frame_128_13_0}; |  | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||||
| const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | ||||||
| @ -478,12 +472,10 @@ const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.fr | |||||||
| const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; | const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; | ||||||
| const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; | const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; | ||||||
| const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; | const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; | ||||||
| const Icon I_quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_quest_7x8}; | const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; | ||||||
| const Icon I_unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_unlock_7x8}; | const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; | ||||||
| const Icon I_Scanning_dolph_67_61 = {.width=67,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_dolph_67_61}; | const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; | ||||||
| const Icon I_Broadcast_dolph_67_61 = {.width=67,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_Broadcast_dolph_67_61}; | const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; | ||||||
| const Icon I_lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_lock_7x8}; |  | ||||||
| const Icon I_Top_frame_128_13 = {.width=128,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Top_frame_128_13}; |  | ||||||
| const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | ||||||
| const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56}; | const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56}; | ||||||
| const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | ||||||
|  | |||||||
| @ -29,12 +29,10 @@ extern const Icon I_DolphinFirstStart8_56x51; | |||||||
| extern const Icon I_DolphinFirstStart7_61x51; | extern const Icon I_DolphinFirstStart7_61x51; | ||||||
| extern const Icon I_Flipper_young_80x60; | extern const Icon I_Flipper_young_80x60; | ||||||
| extern const Icon I_DolphinFirstStart3_57x48; | extern const Icon I_DolphinFirstStart3_57x48; | ||||||
| extern const Icon I_quest_7x8; | extern const Icon I_Scanning_123x52; | ||||||
| extern const Icon I_unlock_7x8; | extern const Icon I_Quest_7x8; | ||||||
| extern const Icon I_Scanning_dolph_67_61; | extern const Icon I_Unlock_7x8; | ||||||
| extern const Icon I_Broadcast_dolph_67_61; | extern const Icon I_Lock_7x8; | ||||||
| extern const Icon I_lock_7x8; |  | ||||||
| extern const Icon I_Top_frame_128_13; |  | ||||||
| extern const Icon I_PassportBottom_128x17; | extern const Icon I_PassportBottom_128x17; | ||||||
| extern const Icon I_DoorLeft_8x56; | extern const Icon I_DoorLeft_8x56; | ||||||
| extern const Icon I_DoorLocked_10x56; | extern const Icon I_DoorLocked_10x56; | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/GubGHz/Scanning_123x52.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/GubGHz/Scanning_123x52.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.7 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.4 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.5 KiB | 
| @ -1,144 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| struct used for handling SPI info. |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     SPI_HandleTypeDef* spi; |  | ||||||
|     PubSubCallback cb; |  | ||||||
|     void* ctx; |  | ||||||
| } SpiHandle; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| For transmit/receive data use `spi_xfer` function. |  | ||||||
| 
 |  | ||||||
| * `tx_data` and `rx_data` size must be equal (and equal `len`) |  | ||||||
| * `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback. |  | ||||||
| */ |  | ||||||
| bool spi_xfer( |  | ||||||
|     SPI_HandleTypeDef* spi, |  | ||||||
|     uint8_t* tx_data, |  | ||||||
|     uint8_t* rx_data, |  | ||||||
|     size_t len, |  | ||||||
|     PubSubCallback cb, |  | ||||||
|     void* ctx); |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Blocking verison: |  | ||||||
| */ |  | ||||||
| static inline bool |  | ||||||
|     spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) { |  | ||||||
|     semaphoreInfo s; |  | ||||||
|     osSemaphore block = createSemaphoreStatic(s); |  | ||||||
|     if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) { |  | ||||||
|         osReleaseSemaphore(block); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     osWaitSemaphore(block); |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Common implementation of SPI bus: serial interface + CS pin |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     GpioPin* cs; ///< CS pin
 |  | ||||||
|     ValueMutex* spi; ///< <SpiHandle*>
 |  | ||||||
| } SpiBus; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| For dedicated work with one device there is `SpiDevice` entity. |  | ||||||
| It contains ValueMutex around SpiBus: after you acquire device |  | ||||||
| you can acquire spi to work with it (don't forget SPI bus is shared |  | ||||||
| around many device, release it after every transaction as quick as possible). |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <SpiBus*>
 |  | ||||||
| } SpiDevice; |  | ||||||
| 
 |  | ||||||
| ##SPI IRQ device |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
| Many devices (like CC1101 and NFC) present as SPI bus and IRQ line. |  | ||||||
| For work with it there is special entity `SpiIrqDevice`. |  | ||||||
| Use `subscribe_pubsub` for subscribinq to irq events. |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
|     typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <SpiBus*>
 |  | ||||||
|     PubSub* irq; |  | ||||||
| } SpiIrqDevice; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Special implementation of SPI bus: serial interface + CS, Res, D/I lines. |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     GpioPin* cs; ///< CS pin
 |  | ||||||
|     GpioPin* res; ///< reset pin
 |  | ||||||
|     GpioPin* di; ///< D/I pin
 |  | ||||||
|     ValueMutex* spi; ///< <SPI_HandleTypeDef*>
 |  | ||||||
| } DisplayBus; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <DisplayBus*>
 |  | ||||||
| } DisplayDevice; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| # SPI devices (F2) |  | ||||||
| 
 |  | ||||||
| * `/dev/sdcard` - SD card SPI, `SpiDevice` |  | ||||||
| * `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice` |  | ||||||
| * `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice` |  | ||||||
| * `/dev/display` - `DisplayDevice` |  | ||||||
| * `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7) |  | ||||||
| 
 |  | ||||||
| ### Application example |  | ||||||
| 
 |  | ||||||
| ```C |  | ||||||
| // Be careful, this function called from IRQ context
 |  | ||||||
| void handle_irq(void* _arg, void* _ctx) { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void cc1101_example() { |  | ||||||
|     SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus"); |  | ||||||
|     if(cc1101_device == NULL) return; // bus not available, critical error
 |  | ||||||
| 
 |  | ||||||
|     subscribe_pubsub(cc1101_device->irq, handle_irq, NULL); |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         // acquire device as device bus
 |  | ||||||
|         SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0); |  | ||||||
|         if(spi_bus == NULL) { |  | ||||||
|             printf("Device busy\n"); |  | ||||||
|             // wait for device
 |  | ||||||
|             spi_bus = acquire_mutex_block(cc1101_device->bus); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // make transaction
 |  | ||||||
|         uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF}; |  | ||||||
|         uint8_t response[4]; |  | ||||||
| 
 |  | ||||||
|         { |  | ||||||
|             SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi); |  | ||||||
| 
 |  | ||||||
|             gpio_write(spi_bus->cs, false); |  | ||||||
|             spi_xfer_block(spi, request, response, 4); |  | ||||||
|             gpio_write(spi_bus->cs, true); |  | ||||||
| 
 |  | ||||||
|             release_mutex(cc1101_device->spi, spi); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // release device (device bus)
 |  | ||||||
|         release_mutex(cc1101_device->bus, spi_bus); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @ -31,3 +31,12 @@ | |||||||
| #ifndef COUNT_OF | #ifndef COUNT_OF | ||||||
| #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) | #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef FURI_SWAP | ||||||
|  | #define FURI_SWAP(x, y)     \ | ||||||
|  |     do {                    \ | ||||||
|  |         typeof(x) SWAP = x; \ | ||||||
|  |         x = y;              \ | ||||||
|  |         y = SWAP;           \ | ||||||
|  |     } while(0) | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -22,7 +22,9 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance); | |||||||
|  * @param encoder - SubGhzProtocolCommonEncoder encoder |  * @param encoder - SubGhzProtocolCommonEncoder encoder | ||||||
|  * @return bool |  * @return bool | ||||||
|  */ |  */ | ||||||
| bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolCommonEncoder* encoder); | bool subghz_protocol_came_send_key( | ||||||
|  |     SubGhzProtocolCame* instance, | ||||||
|  |     SubGhzProtocolCommonEncoder* encoder); | ||||||
| 
 | 
 | ||||||
| /** Reset internal state
 | /** Reset internal state
 | ||||||
|  * @param instance - SubGhzProtocolCame instance |  * @param instance - SubGhzProtocolCame instance | ||||||
| @ -43,6 +45,26 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32 | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output); | void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolCame instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output); | void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output); | ||||||
| bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolCame* instance); | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolCame instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
|  | bool subghz_protocol_came_to_load_protocol_from_file( | ||||||
|  |     FileWorker* file_worker, | ||||||
|  |     SubGhzProtocolCame* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolCame instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context); | void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context); | ||||||
| @ -96,9 +96,30 @@ struct SubGhzProtocolCommonLoad{ | |||||||
|     uint32_t param3; |     uint32_t param3; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /** Allocate SubGhzProtocolCommonEncoder
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzProtocolCommonEncoder*  | ||||||
|  |  */ | ||||||
| SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc(); | SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc(); | ||||||
|  | 
 | ||||||
|  | /** Free SubGhzProtocolCommonEncoder
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  | ||||||
|  |  */ | ||||||
| void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance); | void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance); | ||||||
|  | 
 | ||||||
|  | /** Get count repeat left
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolCommonEncoder instance | ||||||
|  |  * @return count repeat left | ||||||
|  |  */ | ||||||
| size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance); | size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance); | ||||||
|  | 
 | ||||||
|  | /** Get LevelDuration this encoder step
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzProtocolCommonEncoder context | ||||||
|  |  * @return LevelDuration this step | ||||||
|  |  */ | ||||||
| LevelDuration subghz_protocol_encoder_common_yield(void* context); | LevelDuration subghz_protocol_encoder_common_yield(void* context); | ||||||
| 
 | 
 | ||||||
| /** Add data bit to code_found
 | /** Add data bit to code_found
 | ||||||
| @ -146,4 +167,11 @@ void subghz_protocol_common_set_callback( | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output); | void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Converting a string to a HEX array
 | ||||||
|  |  *  | ||||||
|  |  * @param str - string data | ||||||
|  |  * @param buff - uint8_t* buff | ||||||
|  |  * @param len - size buff | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
| bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len); | bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len); | ||||||
|  | |||||||
| @ -50,4 +50,9 @@ void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level, | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output); | void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolFaacSLH instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context); | void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context); | ||||||
|  | |||||||
| @ -43,6 +43,24 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output); | void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolGateTX instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output); | void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolGateTX instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
| bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance); | bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolGateTX instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context); | void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context); | ||||||
|  | |||||||
| @ -49,4 +49,10 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t | |||||||
|  * @param output   - output string |  * @param output   - output string | ||||||
|  */ |  */ | ||||||
| void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output); | void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolIDo instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context); | void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context); | ||||||
|  | |||||||
| @ -174,15 +174,31 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan | |||||||
|     instance->common.btn = key_fix >> 28; |     instance->common.btn = key_fix >> 28; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* subghz_protocol_keeloq_get_manufacture_name(void* context) { | const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context) { | ||||||
|     SubGhzProtocolKeeloq* instance = context; |     SubGhzProtocolKeeloq* instance = context; | ||||||
|     subghz_protocol_keeloq_check_remote_controller(instance); |     subghz_protocol_keeloq_check_remote_controller(instance); | ||||||
|     return instance->manufacture_name; |     return instance->manufacture_name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) { | const char* subghz_protocol_keeloq_get_manufacture_name(void* context) { | ||||||
|  |     SubGhzProtocolKeeloq* instance = context; | ||||||
|  |     return instance->manufacture_name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) { | ||||||
|     SubGhzProtocolKeeloq* instance = context; |     SubGhzProtocolKeeloq* instance = context; | ||||||
|     instance->manufacture_name = manufacture_name; |     instance->manufacture_name = manufacture_name; | ||||||
|  |     int res = 0; | ||||||
|  |         for | ||||||
|  |             M_EACH( | ||||||
|  |                 manufacture_code, | ||||||
|  |                 *subghz_keystore_get_data(instance->keystore), | ||||||
|  |                 SubGhzKeyArray_t) { | ||||||
|  |                 res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name); | ||||||
|  |                 if(res == 0) return true; | ||||||
|  |             } | ||||||
|  |         instance->manufacture_name = "Unknown"; | ||||||
|  |         return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint64_t subghz_protocol_keeloq_gen_key(void* context) { | uint64_t subghz_protocol_keeloq_gen_key(void* context) { | ||||||
| @ -232,6 +248,10 @@ bool subghz_protocol_keeloq_send_key( | |||||||
|     if(instance->common.callback) |     if(instance->common.callback) | ||||||
|         instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); |         instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); | ||||||
| 
 | 
 | ||||||
|  |     if(!strcmp(instance->manufacture_name, "Unknown")) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     size_t index = 0; |     size_t index = 0; | ||||||
|     encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4; |     encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4; | ||||||
|     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; |     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; | ||||||
| @ -392,8 +412,7 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp | |||||||
|         code_found_reverse_lo, |         code_found_reverse_lo, | ||||||
|         instance->common.btn, |         instance->common.btn, | ||||||
|         instance->manufacture_name, |         instance->manufacture_name, | ||||||
|         instance->common.serial |         instance->common.serial); | ||||||
|     ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) { | void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) { | ||||||
| @ -450,9 +469,7 @@ bool subghz_protocol_keeloq_to_load_protocol_from_file( | |||||||
|     return loaded; |     return loaded; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_decoder_keeloq_to_load_protocol( | void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context) { | ||||||
|     SubGhzProtocolKeeloq* instance, |  | ||||||
|     void* context) { |  | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     SubGhzProtocolCommonLoad* data = context; |     SubGhzProtocolCommonLoad* data = context; | ||||||
|  | |||||||
| @ -18,14 +18,27 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore); | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance); | void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance); | ||||||
| 
 | 
 | ||||||
|  | /** Find and get manufacture name
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzProtocolKeeloq context | ||||||
|  |  * @return name - char* manufacture name | ||||||
|  |  */ | ||||||
|  | const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context); | ||||||
|  | 
 | ||||||
|  | /** Get manufacture name
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzProtocolKeeloq context | ||||||
|  |  * @return name - char* manufacture name | ||||||
|  |  */ | ||||||
| const char* subghz_protocol_keeloq_get_manufacture_name(void* context); | const char* subghz_protocol_keeloq_get_manufacture_name(void* context); | ||||||
| 
 | 
 | ||||||
| /** Set manufacture name
 | /** Set manufacture name
 | ||||||
|  *  |  *  | ||||||
|  * @param manufacture_name - manufacture name |  * @param manufacture_name - manufacture name | ||||||
|  * @param context - SubGhzProtocolKeeloq context |  * @param context - SubGhzProtocolKeeloq context | ||||||
|  |  * @return bool | ||||||
|  */ |  */ | ||||||
| void subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name); | bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name); | ||||||
| 
 | 
 | ||||||
| /** Get key keeloq
 | /** Get key keeloq
 | ||||||
|  *  |  *  | ||||||
| @ -61,6 +74,24 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output); | void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolKeeloq instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output); | void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolKeeloq instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
| bool subghz_protocol_keeloq_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolKeeloq* instance); | bool subghz_protocol_keeloq_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolKeeloq* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolKeeloq instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context); | void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context); | ||||||
|  | |||||||
| @ -49,6 +49,24 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output); | void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolNeroSketch instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output); | void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolNeroSketch instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
| bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance); | bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNeroSketch instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context); | void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context); | ||||||
| @ -43,6 +43,24 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output); | void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzProtocolNiceFlo instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output); | void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzProtocolNiceFlo instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
| bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance); | bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNiceFlo instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context); | void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context); | ||||||
|  | |||||||
| @ -50,4 +50,10 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool l | |||||||
|  * @param output   - output string |  * @param output   - output string | ||||||
|  */ |  */ | ||||||
| void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output); | void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNiceFlorS instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context); | void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context); | ||||||
| @ -56,6 +56,11 @@ SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(); | |||||||
|  */ |  */ | ||||||
| void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance); | void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance); | ||||||
| 
 | 
 | ||||||
|  | /** Get Te interval protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzDecoderPrinceton context | ||||||
|  |  * @return Te interval (us) | ||||||
|  |  */ | ||||||
| uint16_t subghz_protocol_princeton_get_te(void* context); | uint16_t subghz_protocol_princeton_get_te(void* context); | ||||||
| 
 | 
 | ||||||
| /** Get upload protocol
 | /** Get upload protocol
 | ||||||
| @ -90,11 +95,26 @@ void subghz_decoder_princeton_parse( | |||||||
|  */ |  */ | ||||||
| void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output); | void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output); | ||||||
| 
 | 
 | ||||||
|  | /** Get a string to save the protocol
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzDecoderPrinceton instance | ||||||
|  |  * @param output    - the resulting string | ||||||
|  |  */ | ||||||
| void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output); | void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output); | ||||||
| bool subghz_decoder_princeton_to_load_protocol_from_file( |  | ||||||
|     FileWorker* file_worker, |  | ||||||
|     SubGhzDecoderPrinceton* instance); |  | ||||||
| 
 | 
 | ||||||
|  | /** Loading protocol from file
 | ||||||
|  |  *  | ||||||
|  |  * @param file_worker - FileWorker file_worker | ||||||
|  |  * @param instance - SubGhzDecoderPrinceton instance | ||||||
|  |  * @return bool | ||||||
|  |  */ | ||||||
|  | bool subghz_decoder_princeton_to_load_protocol_from_file(FileWorker* file_worker, SubGhzDecoderPrinceton* instance); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzDecoderPrinceton instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_princeton_to_load_protocol( | void subghz_decoder_princeton_to_load_protocol( | ||||||
|     SubGhzDecoderPrinceton* instance, |     SubGhzDecoderPrinceton* instance, | ||||||
|     void* context) ; |     void* context) ; | ||||||
|  | |||||||
| @ -38,12 +38,17 @@ void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) { | |||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* subghz_protocol_star_line_get_manufacture_name (void* context){ | const char* subghz_protocol_star_line_find_and_get_manufacture_name (void* context){ | ||||||
|     SubGhzProtocolStarLine* instance = context; |     SubGhzProtocolStarLine* instance = context; | ||||||
|     subghz_protocol_star_line_check_remote_controller(instance); |     subghz_protocol_star_line_check_remote_controller(instance); | ||||||
|     return instance->manufacture_name; |     return instance->manufacture_name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const char* subghz_protocol_star_line_get_manufacture_name (void* context){ | ||||||
|  |     SubGhzProtocolStarLine* instance = context; | ||||||
|  |     return instance->manufacture_name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** Send bit 
 | /** Send bit 
 | ||||||
|  *  |  *  | ||||||
|  * @param instance - SubGhzProtocolStarLine instance |  * @param instance - SubGhzProtocolStarLine instance | ||||||
|  | |||||||
| @ -18,6 +18,18 @@ SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore | |||||||
|  */ |  */ | ||||||
| void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance); | void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance); | ||||||
| 
 | 
 | ||||||
|  | /** Find and get manufacture name
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzProtocolStarLine context | ||||||
|  |  * @return name - char* manufacture name | ||||||
|  |  */ | ||||||
|  | const char* subghz_protocol_star_line_find_and_get_manufacture_name(void* context); | ||||||
|  | 
 | ||||||
|  | /** Get manufacture name
 | ||||||
|  |  *  | ||||||
|  |  * @param context - SubGhzProtocolStarLine context | ||||||
|  |  * @return name - char* manufacture name | ||||||
|  |  */ | ||||||
| const char* subghz_protocol_star_line_get_manufacture_name(void* context); | const char* subghz_protocol_star_line_get_manufacture_name(void* context); | ||||||
| 
 | 
 | ||||||
| /** Sends the key on the air
 | /** Sends the key on the air
 | ||||||
| @ -53,4 +65,10 @@ void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool leve | |||||||
|  * @param output   - output string |  * @param output   - output string | ||||||
|  */ |  */ | ||||||
| void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output); | void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Loading protocol from bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzDecoderPrinceton instance | ||||||
|  |  * @param context - SubGhzProtocolCommonLoad context | ||||||
|  |  */ | ||||||
| void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context); | void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context); | ||||||
|  | |||||||
| @ -16,10 +16,28 @@ ARRAY_DEF(SubGhzKeyArray, SubGhzKey, M_POD_OPLIST) | |||||||
| 
 | 
 | ||||||
| typedef struct SubGhzKeystore SubGhzKeystore; | typedef struct SubGhzKeystore SubGhzKeystore; | ||||||
| 
 | 
 | ||||||
|  | /** Allocate SubGhzKeystore
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzKeystore*  | ||||||
|  |  */ | ||||||
| SubGhzKeystore* subghz_keystore_alloc(); | SubGhzKeystore* subghz_keystore_alloc(); | ||||||
| 
 | 
 | ||||||
|  | /** Free SubGhzKeystore
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  | ||||||
|  |  */ | ||||||
| void subghz_keystore_free(SubGhzKeystore* instance); | void subghz_keystore_free(SubGhzKeystore* instance); | ||||||
| 
 | 
 | ||||||
|  | /** Loading manufacture key from file
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzKeystore instance | ||||||
|  |  * @param filename - const char* full path to the file | ||||||
|  |  */ | ||||||
| void subghz_keystore_load(SubGhzKeystore* instance, const char* filename); | void subghz_keystore_load(SubGhzKeystore* instance, const char* filename); | ||||||
| 
 | 
 | ||||||
|  | /** Get array of keys and names manufacture
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzKeystore instance | ||||||
|  |  * @return SubGhzKeyArray_t* | ||||||
|  |  */ | ||||||
| SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance); | SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm