[FL-1755, FL-1756] added LL_DeInit timers, removed Analyze scene, redesigned astomatic frequency change mechanism, updated subghz read scene interface (#677)
* SubGhz: Fix Timer hopping * SubGhz: add display of received packages and their maximum number. redesigned interface, the maximum number of received packages increased to 50 * SubGhz: add clearing history on exit read scene, jump after saving the key into the history of received signals * SubGhz: Fix honoring the width of the icon for transmitter scene * RFID: Fix [FL-1755] freeze after key emulation * SubGhz: drop analyze scene and views * SubGhz: fix save scene * Input, GUI: new event delivery scheme that groups event for complementarity. * Gui: update View Dispatcher documentation * Gui: remove dead code, wait till all input events are delivered in ViewDispatcher in queue mode. * Gui: update comment in ViewDispatcher * FuriHal: fix incorrect clock disable invocation * FuriHal: proper include * SubGhz: properly reset history in receiver view * Gui: correct view switch order and non-complementary events discarding Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									8b9210704a
								
							
						
					
					
						commit
						6f7bcdf9a7
					
				@ -11,6 +11,8 @@ struct ViewHolder {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    BackCallback back_callback;
 | 
					    BackCallback back_callback;
 | 
				
			||||||
    void* back_context;
 | 
					    void* back_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t ongoing_input_events_count;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void view_holder_draw_callback(Canvas* canvas, void* context);
 | 
					static void view_holder_draw_callback(Canvas* canvas, void* context);
 | 
				
			||||||
@ -92,6 +94,7 @@ void view_holder_start(ViewHolder* view_holder) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_holder_stop(ViewHolder* view_holder) {
 | 
					void view_holder_stop(ViewHolder* view_holder) {
 | 
				
			||||||
 | 
					    while(view_holder->ongoing_input_events_count > 0) osDelay(1);
 | 
				
			||||||
    view_port_enabled_set(view_holder->view_port, false);
 | 
					    view_port_enabled_set(view_holder->view_port, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -114,6 +117,16 @@ static void view_holder_draw_callback(Canvas* canvas, void* context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void view_holder_input_callback(InputEvent* event, void* context) {
 | 
					static void view_holder_input_callback(InputEvent* event, void* context) {
 | 
				
			||||||
    ViewHolder* view_holder = context;
 | 
					    ViewHolder* view_holder = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(event->type == InputTypeRelease && view_holder->ongoing_input_events_count > 0) {
 | 
				
			||||||
 | 
					        view_holder->ongoing_input_events_count--;
 | 
				
			||||||
 | 
					    } else if(event->type == InputTypePress) {
 | 
				
			||||||
 | 
					        view_holder->ongoing_input_events_count++;
 | 
				
			||||||
 | 
					    } else if(view_holder->ongoing_input_events_count == 0) {
 | 
				
			||||||
 | 
					        FURI_LOG_E("ViewHolder", "non-complementary input, discarding");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool is_consumed = false;
 | 
					    bool is_consumed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(view_holder->view) {
 | 
					    if(view_holder->view) {
 | 
				
			||||||
 | 
				
			|||||||
@ -35,11 +35,6 @@ void view_set_previous_callback(View* view, ViewNavigationCallback callback) {
 | 
				
			|||||||
    view->previous_callback = callback;
 | 
					    view->previous_callback = callback;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_set_next_callback(View* view, ViewNavigationCallback callback) {
 | 
					 | 
				
			||||||
    furi_assert(view);
 | 
					 | 
				
			||||||
    view->next_callback = callback;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void view_set_enter_callback(View* view, ViewCallback callback) {
 | 
					void view_set_enter_callback(View* view, ViewCallback callback) {
 | 
				
			||||||
    furi_assert(view);
 | 
					    furi_assert(view);
 | 
				
			||||||
    view->enter_callback = callback;
 | 
					    view->enter_callback = callback;
 | 
				
			||||||
@ -169,15 +164,6 @@ uint32_t view_previous(View* view) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t view_next(View* view) {
 | 
					 | 
				
			||||||
    furi_assert(view);
 | 
					 | 
				
			||||||
    if(view->next_callback) {
 | 
					 | 
				
			||||||
        return view->next_callback(view->context);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        return VIEW_IGNORE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void view_enter(View* view) {
 | 
					void view_enter(View* view) {
 | 
				
			||||||
    furi_assert(view);
 | 
					    furi_assert(view);
 | 
				
			||||||
    if(view->enter_callback) view->enter_callback(view->context);
 | 
					    if(view->enter_callback) view->enter_callback(view->context);
 | 
				
			||||||
 | 
				
			|||||||
@ -14,11 +14,6 @@ extern "C" {
 | 
				
			|||||||
#define VIEW_NONE 0xFFFFFFFF
 | 
					#define VIEW_NONE 0xFFFFFFFF
 | 
				
			||||||
/* Ignore navigation event */
 | 
					/* Ignore navigation event */
 | 
				
			||||||
#define VIEW_IGNORE 0xFFFFFFFE
 | 
					#define VIEW_IGNORE 0xFFFFFFFE
 | 
				
			||||||
/* Deatch from gui, deallocate Views and ViewDispatcher
 | 
					 | 
				
			||||||
 * BE SUPER CAREFUL, deallocation happens automatically on GUI thread
 | 
					 | 
				
			||||||
 * You ARE NOT owning ViewDispatcher and Views instances
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define VIEW_DESTROY 0xFFFFFFFA
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    ViewOrientationHorizontal,
 | 
					    ViewOrientationHorizontal,
 | 
				
			||||||
@ -119,12 +114,6 @@ void view_set_custom_callback(View* view, ViewCustomCallback callback);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
void view_set_previous_callback(View* view, ViewNavigationCallback callback);
 | 
					void view_set_previous_callback(View* view, ViewNavigationCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Set Navigation Next callback
 | 
					 | 
				
			||||||
 * @param view, pointer to View
 | 
					 | 
				
			||||||
 * @param callback, input callback
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void view_set_next_callback(View* view, ViewNavigationCallback callback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Set Enter callback
 | 
					/* Set Enter callback
 | 
				
			||||||
 * @param view, pointer to View
 | 
					 * @param view, pointer to View
 | 
				
			||||||
 * @param callback, callback
 | 
					 * @param callback, callback
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								applications/gui/view_dispatcher.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										39
									
								
								applications/gui/view_dispatcher.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -91,6 +91,18 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
 | 
				
			|||||||
            view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event);
 | 
					            view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Wait till all input events delivered
 | 
				
			||||||
 | 
					    while(view_dispatcher->ongoing_input_events_count > 0) {
 | 
				
			||||||
 | 
					        osMessageQueueGet(view_dispatcher->queue, &message, NULL, osWaitForever);
 | 
				
			||||||
 | 
					        if(message.type == ViewDispatcherMessageTypeInput) {
 | 
				
			||||||
 | 
					            if(message.input.type == InputTypePress) {
 | 
				
			||||||
 | 
					                view_dispatcher->ongoing_input_events_count++;
 | 
				
			||||||
 | 
					            } else if(message.input.type == InputTypeRelease) {
 | 
				
			||||||
 | 
					                view_dispatcher->ongoing_input_events_count--;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_dispatcher_stop(ViewDispatcher* view_dispatcher) {
 | 
					void view_dispatcher_stop(ViewDispatcher* view_dispatcher) {
 | 
				
			||||||
@ -153,12 +165,15 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
 | 
				
			|||||||
    if(view_id == VIEW_NONE) {
 | 
					    if(view_id == VIEW_NONE) {
 | 
				
			||||||
        view_dispatcher_set_current_view(view_dispatcher, NULL);
 | 
					        view_dispatcher_set_current_view(view_dispatcher, NULL);
 | 
				
			||||||
    } else if(view_id == VIEW_IGNORE) {
 | 
					    } else if(view_id == VIEW_IGNORE) {
 | 
				
			||||||
    } else if(view_id == VIEW_DESTROY) {
 | 
					 | 
				
			||||||
        view_dispatcher_free(view_dispatcher);
 | 
					 | 
				
			||||||
    } 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);
 | 
				
			||||||
        view_dispatcher_set_current_view(view_dispatcher, *view_pp);
 | 
					        if(view_dispatcher->ongoing_input_events_count > 0) {
 | 
				
			||||||
 | 
					            view_dispatcher->delayed_next_view = *view_pp;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            view_dispatcher->delayed_next_view = NULL;
 | 
				
			||||||
 | 
					            view_dispatcher_set_current_view(view_dispatcher, *view_pp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -202,6 +217,16 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) {
 | 
					void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) {
 | 
				
			||||||
 | 
					    // Ongoing input events counting
 | 
				
			||||||
 | 
					    if(event->type == InputTypeRelease && view_dispatcher->ongoing_input_events_count > 0) {
 | 
				
			||||||
 | 
					        view_dispatcher->ongoing_input_events_count--;
 | 
				
			||||||
 | 
					    } else if(event->type == InputTypePress) {
 | 
				
			||||||
 | 
					        view_dispatcher->ongoing_input_events_count++;
 | 
				
			||||||
 | 
					    } else if(view_dispatcher->ongoing_input_events_count == 0) {
 | 
				
			||||||
 | 
					        FURI_LOG_E("ViewDispatcher", "non-complementary input, discarding");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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);
 | 
				
			||||||
@ -219,13 +244,17 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
 | 
				
			|||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if(event->key == InputKeyOk) {
 | 
					 | 
				
			||||||
            view_id = view_next(view_dispatcher->current_view);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if(!is_consumed) {
 | 
					        if(!is_consumed) {
 | 
				
			||||||
            view_dispatcher_switch_to_view(view_dispatcher, view_id);
 | 
					            view_dispatcher_switch_to_view(view_dispatcher, view_id);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Delayed view switch
 | 
				
			||||||
 | 
					    if(view_dispatcher->delayed_next_view && view_dispatcher->ongoing_input_events_count == 0) {
 | 
				
			||||||
 | 
					        view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view);
 | 
				
			||||||
 | 
					        view_dispatcher->delayed_next_view = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_dispatcher_handle_tick_event(ViewDispatcher* view_dispatcher) {
 | 
					void view_dispatcher_handle_tick_event(ViewDispatcher* view_dispatcher) {
 | 
				
			||||||
 | 
				
			|||||||
@ -113,6 +113,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
 | 
				
			|||||||
/** Switch to View
 | 
					/** Switch to View
 | 
				
			||||||
 * @param view_dispatcher ViewDispatcher instance
 | 
					 * @param view_dispatcher ViewDispatcher instance
 | 
				
			||||||
 * @param view_id View id to register
 | 
					 * @param view_id View id to register
 | 
				
			||||||
 | 
					 * @warning switching may be delayed till input events complementarity reached
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id);
 | 
					void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,12 @@ struct ViewDispatcher {
 | 
				
			|||||||
    Gui* gui;
 | 
					    Gui* gui;
 | 
				
			||||||
    ViewPort* view_port;
 | 
					    ViewPort* view_port;
 | 
				
			||||||
    ViewDict_t views;
 | 
					    ViewDict_t views;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    View* current_view;
 | 
					    View* current_view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    View* delayed_next_view;
 | 
				
			||||||
 | 
					    uint8_t ongoing_input_events_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ViewDispatcherCustomEventCallback custom_event_callback;
 | 
					    ViewDispatcherCustomEventCallback custom_event_callback;
 | 
				
			||||||
    ViewDispatcherNavigationEventCallback navigation_event_callback;
 | 
					    ViewDispatcherNavigationEventCallback navigation_event_callback;
 | 
				
			||||||
    ViewDispatcherTickEventCallback tick_event_callback;
 | 
					    ViewDispatcherTickEventCallback tick_event_callback;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,6 @@ struct View {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ViewModelType model_type;
 | 
					    ViewModelType model_type;
 | 
				
			||||||
    ViewNavigationCallback previous_callback;
 | 
					    ViewNavigationCallback previous_callback;
 | 
				
			||||||
    ViewNavigationCallback next_callback;
 | 
					 | 
				
			||||||
    ViewCallback enter_callback;
 | 
					    ViewCallback enter_callback;
 | 
				
			||||||
    ViewCallback exit_callback;
 | 
					    ViewCallback exit_callback;
 | 
				
			||||||
    ViewOrientation orientation;
 | 
					    ViewOrientation orientation;
 | 
				
			||||||
@ -42,9 +41,6 @@ bool view_custom(View* view, uint32_t event);
 | 
				
			|||||||
/* Previous Callback for View dispatcher */
 | 
					/* Previous Callback for View dispatcher */
 | 
				
			||||||
uint32_t view_previous(View* view);
 | 
					uint32_t view_previous(View* view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Next Callback for View dispatcher */
 | 
					 | 
				
			||||||
uint32_t view_next(View* view);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Enter Callback for View dispatcher */
 | 
					/* Enter Callback for View dispatcher */
 | 
				
			||||||
void view_enter(View* view);
 | 
					void view_enter(View* view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -131,9 +131,6 @@ int32_t input_srv() {
 | 
				
			|||||||
                // Common state info
 | 
					                // Common state info
 | 
				
			||||||
                InputEvent event;
 | 
					                InputEvent event;
 | 
				
			||||||
                event.key = input->pin_states[i].pin->key;
 | 
					                event.key = input->pin_states[i].pin->key;
 | 
				
			||||||
                event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease;
 | 
					 | 
				
			||||||
                // Send Press/Release event
 | 
					 | 
				
			||||||
                notify_pubsub(&input->event_pubsub, &event);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Short / Long / Repeat timer routine
 | 
					                // Short / Long / Repeat timer routine
 | 
				
			||||||
                if(state) {
 | 
					                if(state) {
 | 
				
			||||||
@ -146,6 +143,10 @@ int32_t input_srv() {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    input->pin_states[i].press_counter = 0;
 | 
					                    input->pin_states[i].press_counter = 0;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Send Press/Release event
 | 
				
			||||||
 | 
					                event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease;
 | 
				
			||||||
 | 
					                notify_pubsub(&input->event_pubsub, &event);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +0,0 @@
 | 
				
			|||||||
#include "../subghz_i.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const void subghz_scene_analyze_on_enter(void* context) {
 | 
					 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					 | 
				
			||||||
    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewAnalyze);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const bool subghz_scene_analyze_on_event(void* context, SceneManagerEvent event) {
 | 
					 | 
				
			||||||
    SubGhz* subghz = context;
 | 
					 | 
				
			||||||
    if(event.type == SceneManagerEventTypeTick) {
 | 
					 | 
				
			||||||
        notification_message(subghz->notifications, &sequence_blink_blue_10);
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const void subghz_scene_analyze_on_exit(void* context) {
 | 
					 | 
				
			||||||
    // SubGhz* subghz = context;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
ADD_SCENE(subghz, start, Start)
 | 
					ADD_SCENE(subghz, start, Start)
 | 
				
			||||||
ADD_SCENE(subghz, analyze, Analyze)
 | 
					 | 
				
			||||||
ADD_SCENE(subghz, receiver, Receiver)
 | 
					ADD_SCENE(subghz, receiver, Receiver)
 | 
				
			||||||
ADD_SCENE(subghz, save_name, SaveName)
 | 
					ADD_SCENE(subghz, save_name, SaveName)
 | 
				
			||||||
ADD_SCENE(subghz, save_success, SaveSuccess)
 | 
					ADD_SCENE(subghz, save_success, SaveSuccess)
 | 
				
			||||||
 | 
				
			|||||||
@ -25,8 +25,12 @@ const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent e
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
 | 
					        if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
 | 
				
			||||||
            return scene_manager_search_and_switch_to_previous_scene(
 | 
					            if(!scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneStart);
 | 
					                   subghz->scene_manager, SubGhzSceneReceiver)) {
 | 
				
			||||||
 | 
					                scene_manager_search_and_switch_to_previous_scene(
 | 
				
			||||||
 | 
					                    subghz->scene_manager, SubGhzSceneStart);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
#include "../subghz_i.h"
 | 
					#include "../subghz_i.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum SubmenuIndex {
 | 
					enum SubmenuIndex {
 | 
				
			||||||
    SubmenuIndexAnalyze,
 | 
					 | 
				
			||||||
    SubmenuIndexRead,
 | 
					    SubmenuIndexRead,
 | 
				
			||||||
    SubmenuIndexSaved,
 | 
					    SubmenuIndexSaved,
 | 
				
			||||||
    SubmenuIndexTest,
 | 
					    SubmenuIndexTest,
 | 
				
			||||||
@ -18,12 +17,6 @@ const void subghz_scene_start_on_enter(void* context) {
 | 
				
			|||||||
    if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) {
 | 
					    if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) {
 | 
				
			||||||
        subghz->state_notifications = NOTIFICATION_IDLE_STATE;
 | 
					        subghz->state_notifications = NOTIFICATION_IDLE_STATE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    submenu_add_item(
 | 
					 | 
				
			||||||
        subghz->submenu,
 | 
					 | 
				
			||||||
        "Analyze",
 | 
					 | 
				
			||||||
        SubmenuIndexAnalyze,
 | 
					 | 
				
			||||||
        subghz_scene_start_submenu_callback,
 | 
					 | 
				
			||||||
        subghz);
 | 
					 | 
				
			||||||
    submenu_add_item(
 | 
					    submenu_add_item(
 | 
				
			||||||
        subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
 | 
					        subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
 | 
				
			||||||
    submenu_add_item(
 | 
					    submenu_add_item(
 | 
				
			||||||
@ -47,12 +40,7 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
 | 
				
			|||||||
    SubGhz* subghz = context;
 | 
					    SubGhz* subghz = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
					    if(event.type == SceneManagerEventTypeCustom) {
 | 
				
			||||||
        if(event.event == SubmenuIndexAnalyze) {
 | 
					        if(event.event == SubmenuIndexRead) {
 | 
				
			||||||
            scene_manager_set_scene_state(
 | 
					 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAnalyze);
 | 
					 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneAnalyze);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        } else if(event.event == SubmenuIndexRead) {
 | 
					 | 
				
			||||||
            scene_manager_set_scene_state(
 | 
					            scene_manager_set_scene_state(
 | 
				
			||||||
                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
 | 
					                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
 | 
				
			||||||
            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
 | 
					            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
 | 
				
			||||||
 | 
				
			|||||||
@ -70,13 +70,6 @@ SubGhz* subghz_alloc() {
 | 
				
			|||||||
    view_dispatcher_add_view(
 | 
					    view_dispatcher_add_view(
 | 
				
			||||||
        subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu));
 | 
					        subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Analyze
 | 
					 | 
				
			||||||
    subghz->subghz_analyze = subghz_analyze_alloc();
 | 
					 | 
				
			||||||
    view_dispatcher_add_view(
 | 
					 | 
				
			||||||
        subghz->view_dispatcher,
 | 
					 | 
				
			||||||
        SubGhzViewAnalyze,
 | 
					 | 
				
			||||||
        subghz_analyze_get_view(subghz->subghz_analyze));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Receiver
 | 
					    // Receiver
 | 
				
			||||||
    subghz->subghz_receiver = subghz_receiver_alloc();
 | 
					    subghz->subghz_receiver = subghz_receiver_alloc();
 | 
				
			||||||
    view_dispatcher_add_view(
 | 
					    view_dispatcher_add_view(
 | 
				
			||||||
@ -159,10 +152,6 @@ void subghz_free(SubGhz* subghz) {
 | 
				
			|||||||
    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
 | 
					    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
 | 
				
			||||||
    subghz_test_static_free(subghz->subghz_test_static);
 | 
					    subghz_test_static_free(subghz->subghz_test_static);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Analyze
 | 
					 | 
				
			||||||
    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze);
 | 
					 | 
				
			||||||
    subghz_analyze_free(subghz->subghz_analyze);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Receiver
 | 
					    // Receiver
 | 
				
			||||||
    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);
 | 
					    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);
 | 
				
			||||||
    subghz_receiver_free(subghz->subghz_receiver);
 | 
					    subghz_receiver_free(subghz->subghz_receiver);
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
#include <furi.h>
 | 
					#include <furi.h>
 | 
				
			||||||
#include <m-string.h>
 | 
					#include <m-string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SUBGHZ_HISTORY_MAX 20
 | 
					#define SUBGHZ_HISTORY_MAX 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
 | 
					typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,7 +88,10 @@ 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) {
 | 
				
			||||||
 | 
					    furi_assert(instance);
 | 
				
			||||||
 | 
					    string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
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) {
 | 
				
			||||||
        string_printf(
 | 
					        string_printf(
 | 
				
			||||||
 | 
				
			|||||||
@ -18,5 +18,6 @@ uint16_t subghz_history_get_item(SubGhzHistory* instance);
 | 
				
			|||||||
uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
 | 
					uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
 | 
				
			||||||
const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
 | 
					const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
 | 
				
			||||||
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);
 | 
				
			||||||
void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
 | 
					void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
 | 
				
			||||||
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
 | 
					SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "subghz.h"
 | 
					#include "subghz.h"
 | 
				
			||||||
#include "views/subghz_analyze.h"
 | 
					 | 
				
			||||||
#include "views/subghz_receiver.h"
 | 
					#include "views/subghz_receiver.h"
 | 
				
			||||||
#include "views/subghz_transmitter.h"
 | 
					#include "views/subghz_transmitter.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -59,7 +58,6 @@ struct SubGhz {
 | 
				
			|||||||
    char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
 | 
					    char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
 | 
				
			||||||
    uint8_t state_notifications;
 | 
					    uint8_t state_notifications;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubghzAnalyze* subghz_analyze;
 | 
					 | 
				
			||||||
    SubghzReceiver* subghz_receiver;
 | 
					    SubghzReceiver* subghz_receiver;
 | 
				
			||||||
    SubghzTransmitter* subghz_transmitter;
 | 
					    SubghzTransmitter* subghz_transmitter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,7 +69,6 @@ struct SubGhz {
 | 
				
			|||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    SubGhzViewMenu,
 | 
					    SubGhzViewMenu,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SubGhzViewAnalyze,
 | 
					 | 
				
			||||||
    SubGhzViewDialogEx,
 | 
					    SubGhzViewDialogEx,
 | 
				
			||||||
    SubGhzViewReceiver,
 | 
					    SubGhzViewReceiver,
 | 
				
			||||||
    SubGhzViewPopup,
 | 
					    SubGhzViewPopup,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,233 +0,0 @@
 | 
				
			|||||||
#include "subghz_analyze.h"
 | 
					 | 
				
			||||||
#include "../subghz_i.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <furi.h>
 | 
					 | 
				
			||||||
#include <furi-hal.h>
 | 
					 | 
				
			||||||
#include <input/input.h>
 | 
					 | 
				
			||||||
#include <gui/elements.h>
 | 
					 | 
				
			||||||
#include <notification/notification-messages.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <lib/subghz/subghz_worker.h>
 | 
					 | 
				
			||||||
#include <lib/subghz/protocols/subghz_protocol.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <assets_icons.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct SubghzAnalyze {
 | 
					 | 
				
			||||||
    View* view;
 | 
					 | 
				
			||||||
    SubGhzWorker* worker;
 | 
					 | 
				
			||||||
    SubGhzProtocol* protocol;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    uint8_t frequency;
 | 
					 | 
				
			||||||
    uint32_t real_frequency;
 | 
					 | 
				
			||||||
    uint32_t counter;
 | 
					 | 
				
			||||||
    string_t text;
 | 
					 | 
				
			||||||
    uint16_t scene;
 | 
					 | 
				
			||||||
    SubGhzProtocolCommon parser;
 | 
					 | 
				
			||||||
} SubghzAnalyzeModel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const char subghz_symbols[] = {'-', '\\', '|', '/'};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) {
 | 
					 | 
				
			||||||
    char buffer[64];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    canvas_set_color(canvas, ColorBlack);
 | 
					 | 
				
			||||||
    canvas_set_font(canvas, FontPrimary);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    snprintf(
 | 
					 | 
				
			||||||
        buffer,
 | 
					 | 
				
			||||||
        sizeof(buffer),
 | 
					 | 
				
			||||||
        "Analyze: %03ld.%03ldMHz %c",
 | 
					 | 
				
			||||||
        model->real_frequency / 1000000 % 1000,
 | 
					 | 
				
			||||||
        model->real_frequency / 1000 % 1000,
 | 
					 | 
				
			||||||
        subghz_symbols[model->counter % 4]);
 | 
					 | 
				
			||||||
    canvas_draw_str(canvas, 0, 8, buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch(model->scene) {
 | 
					 | 
				
			||||||
    case 1:
 | 
					 | 
				
			||||||
        canvas_draw_icon(canvas, 0, 10, &I_RFIDDolphinReceive_97x61);
 | 
					 | 
				
			||||||
        canvas_invert_color(canvas);
 | 
					 | 
				
			||||||
        canvas_draw_box(canvas, 80, 12, 20, 20);
 | 
					 | 
				
			||||||
        canvas_invert_color(canvas);
 | 
					 | 
				
			||||||
        canvas_draw_icon(canvas, 75, 18, &I_sub1_10px);
 | 
					 | 
				
			||||||
        elements_multiline_text_aligned(
 | 
					 | 
				
			||||||
            canvas, 90, 38, AlignCenter, AlignTop, "Detecting\r\nSubGhz");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
        canvas_set_font(canvas, FontSecondary);
 | 
					 | 
				
			||||||
        elements_multiline_text(canvas, 0, 18, string_get_cstr(model->text));
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool subghz_analyze_input(InputEvent* event, void* context) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(event->type != InputTypeShort) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(event->key == InputKeyBack) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            bool model_updated = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(event->key == InputKeyLeft) {
 | 
					 | 
				
			||||||
                if(model->frequency > 0) model->frequency--;
 | 
					 | 
				
			||||||
                model_updated = true;
 | 
					 | 
				
			||||||
            } else if(event->key == InputKeyRight) {
 | 
					 | 
				
			||||||
                if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
 | 
					 | 
				
			||||||
                model_updated = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(model_updated) {
 | 
					 | 
				
			||||||
                furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
                model->real_frequency =
 | 
					 | 
				
			||||||
                    furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
 | 
					 | 
				
			||||||
                furi_hal_subghz_rx();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return model_updated;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_text_callback(string_t text, void* context) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            model->counter++;
 | 
					 | 
				
			||||||
            string_set(model->text, text);
 | 
					 | 
				
			||||||
            model->scene = 0;
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = context;
 | 
					 | 
				
			||||||
    char buffer[64];
 | 
					 | 
				
			||||||
    snprintf(
 | 
					 | 
				
			||||||
        buffer,
 | 
					 | 
				
			||||||
        sizeof(buffer),
 | 
					 | 
				
			||||||
        "%s\r\n"
 | 
					 | 
				
			||||||
        "K:%lX%lX\r\n"
 | 
					 | 
				
			||||||
        "SN:%lX\r\n"
 | 
					 | 
				
			||||||
        "BTN:%X",
 | 
					 | 
				
			||||||
        parser->name,
 | 
					 | 
				
			||||||
        (uint32_t)(parser->code_found >> 32),
 | 
					 | 
				
			||||||
        (uint32_t)(parser->code_found & 0x00000000FFFFFFFF),
 | 
					 | 
				
			||||||
        parser->serial,
 | 
					 | 
				
			||||||
        parser->btn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            model->counter++;
 | 
					 | 
				
			||||||
            model->parser = *parser;
 | 
					 | 
				
			||||||
            string_set(model->text, buffer);
 | 
					 | 
				
			||||||
            model->scene = 0;
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_enter(void* context) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_reset();
 | 
					 | 
				
			||||||
    furi_hal_subghz_idle();
 | 
					 | 
				
			||||||
    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            model->frequency = subghz_frequencies_433_92;
 | 
					 | 
				
			||||||
            model->real_frequency =
 | 
					 | 
				
			||||||
                furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
 | 
					 | 
				
			||||||
            model->scene = 1;
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz_analyze->worker);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_worker_start(subghz_analyze->worker);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_flush_rx();
 | 
					 | 
				
			||||||
    furi_hal_subghz_rx();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_exit(void* context) {
 | 
					 | 
				
			||||||
    furi_assert(context);
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_worker_stop(subghz_analyze->worker);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    furi_hal_subghz_stop_async_rx();
 | 
					 | 
				
			||||||
    furi_hal_subghz_sleep();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SubghzAnalyze* subghz_analyze_alloc() {
 | 
					 | 
				
			||||||
    SubghzAnalyze* subghz_analyze = furi_alloc(sizeof(SubghzAnalyze));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // View allocation and configuration
 | 
					 | 
				
			||||||
    subghz_analyze->view = view_alloc();
 | 
					 | 
				
			||||||
    view_allocate_model(subghz_analyze->view, ViewModelTypeLocking, sizeof(SubghzAnalyzeModel));
 | 
					 | 
				
			||||||
    view_set_context(subghz_analyze->view, subghz_analyze);
 | 
					 | 
				
			||||||
    view_set_draw_callback(subghz_analyze->view, (ViewDrawCallback)subghz_analyze_draw);
 | 
					 | 
				
			||||||
    view_set_input_callback(subghz_analyze->view, subghz_analyze_input);
 | 
					 | 
				
			||||||
    view_set_enter_callback(subghz_analyze->view, subghz_analyze_enter);
 | 
					 | 
				
			||||||
    view_set_exit_callback(subghz_analyze->view, subghz_analyze_exit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            string_init(model->text);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_analyze->worker = subghz_worker_alloc();
 | 
					 | 
				
			||||||
    subghz_analyze->protocol = subghz_protocol_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_worker_set_overrun_callback(
 | 
					 | 
				
			||||||
        subghz_analyze->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset);
 | 
					 | 
				
			||||||
    subghz_worker_set_pair_callback(
 | 
					 | 
				
			||||||
        subghz_analyze->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
 | 
					 | 
				
			||||||
    subghz_worker_set_context(subghz_analyze->worker, subghz_analyze->protocol);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_protocol_load_keeloq_file(
 | 
					 | 
				
			||||||
        subghz_analyze->protocol, "/ext/assets/subghz/keeloq_mfcodes");
 | 
					 | 
				
			||||||
    subghz_protocol_load_nice_flor_s_file(
 | 
					 | 
				
			||||||
        subghz_analyze->protocol, "/ext/assets/subghz/nice_floor_s_rx");
 | 
					 | 
				
			||||||
    subghz_protocol_enable_dump_text(
 | 
					 | 
				
			||||||
        subghz_analyze->protocol, subghz_analyze_text_callback, subghz_analyze);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return subghz_analyze;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_free(SubghzAnalyze* subghz_analyze) {
 | 
					 | 
				
			||||||
    furi_assert(subghz_analyze);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    subghz_protocol_free(subghz_analyze->protocol);
 | 
					 | 
				
			||||||
    subghz_worker_free(subghz_analyze->worker);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with_view_model(
 | 
					 | 
				
			||||||
        subghz_analyze->view, (SubghzAnalyzeModel * model) {
 | 
					 | 
				
			||||||
            string_clear(model->text);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    view_free(subghz_analyze->view);
 | 
					 | 
				
			||||||
    free(subghz_analyze);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze) {
 | 
					 | 
				
			||||||
    furi_assert(subghz_analyze);
 | 
					 | 
				
			||||||
    return subghz_analyze->view;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gui/view.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SubghzAnalyze SubghzAnalyze;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SubghzAnalyze* subghz_analyze_alloc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void subghz_analyze_free(SubghzAnalyze* subghz_analyze);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze);
 | 
					 | 
				
			||||||
@ -14,8 +14,8 @@
 | 
				
			|||||||
#define MAX_LEN_PX 100
 | 
					#define MAX_LEN_PX 100
 | 
				
			||||||
#define MENU_ITEMS 4
 | 
					#define MENU_ITEMS 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define COUNT_FREQUNCY_SCANER 3
 | 
					#define COUNT_FREQUNCY_HOPPER 3
 | 
				
			||||||
const uint32_t subghz_frequencies_scanner[] = {
 | 
					const uint32_t subghz_frequencies_hopper[] = {
 | 
				
			||||||
    /* 300 - 348 */
 | 
					    /* 300 - 348 */
 | 
				
			||||||
    315000000,
 | 
					    315000000,
 | 
				
			||||||
    /* 387 - 464 */
 | 
					    /* 387 - 464 */
 | 
				
			||||||
@ -35,6 +35,7 @@ typedef enum {
 | 
				
			|||||||
    SubGhzHopperStateOFF,
 | 
					    SubGhzHopperStateOFF,
 | 
				
			||||||
    SubGhzHopperStatePause,
 | 
					    SubGhzHopperStatePause,
 | 
				
			||||||
    SubGhzHopperStateRunnig,
 | 
					    SubGhzHopperStateRunnig,
 | 
				
			||||||
 | 
					    SubGhzHopperStateRSSITimeOut,
 | 
				
			||||||
} SubGhzHopperState;
 | 
					} SubGhzHopperState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const Icon* ReceiverItemIcons[] = {
 | 
					static const Icon* ReceiverItemIcons[] = {
 | 
				
			||||||
@ -51,6 +52,7 @@ struct SubghzReceiver {
 | 
				
			|||||||
    SubGhzProtocol* protocol;
 | 
					    SubGhzProtocol* protocol;
 | 
				
			||||||
    osTimerId timer;
 | 
					    osTimerId timer;
 | 
				
			||||||
    SubGhzHopperState hopper_state;
 | 
					    SubGhzHopperState hopper_state;
 | 
				
			||||||
 | 
					    uint8_t hopper_timeout;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
@ -62,8 +64,6 @@ typedef struct {
 | 
				
			|||||||
    uint8_t temp_frequency;
 | 
					    uint8_t temp_frequency;
 | 
				
			||||||
    uint32_t real_frequency;
 | 
					    uint32_t real_frequency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t tab_idx;
 | 
					 | 
				
			||||||
    uint8_t menu_idx;
 | 
					 | 
				
			||||||
    uint16_t idx;
 | 
					    uint16_t idx;
 | 
				
			||||||
    uint16_t list_offset;
 | 
					    uint16_t list_offset;
 | 
				
			||||||
    uint16_t history_item;
 | 
					    uint16_t history_item;
 | 
				
			||||||
@ -146,6 +146,7 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
 | 
				
			|||||||
    bool scrollbar = model->history_item > 4;
 | 
					    bool scrollbar = model->history_item > 4;
 | 
				
			||||||
    string_t str_buff;
 | 
					    string_t str_buff;
 | 
				
			||||||
    char buffer[64];
 | 
					    char buffer[64];
 | 
				
			||||||
 | 
					    uint32_t frequency;
 | 
				
			||||||
    string_init(str_buff);
 | 
					    string_init(str_buff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    canvas_clear(canvas);
 | 
					    canvas_clear(canvas);
 | 
				
			||||||
@ -174,15 +175,25 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
 | 
				
			|||||||
            elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
 | 
					            elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        canvas_set_color(canvas, ColorBlack);
 | 
					        canvas_set_color(canvas, ColorBlack);
 | 
				
			||||||
        canvas_set_font(canvas, FontPrimary);
 | 
					        canvas_set_font(canvas, FontSecondary);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elements_button_left(canvas, "Conf");
 | 
				
			||||||
 | 
					        if((model->real_frequency / 1000 % 10) > 4) {
 | 
				
			||||||
 | 
					            frequency = model->real_frequency + 10000;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            frequency = model->real_frequency;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        snprintf(
 | 
					        snprintf(
 | 
				
			||||||
            buffer,
 | 
					            buffer,
 | 
				
			||||||
            sizeof(buffer),
 | 
					            sizeof(buffer),
 | 
				
			||||||
            "%03ld.%03ld  OOK",
 | 
					            "%03ld.%02ld",
 | 
				
			||||||
            model->real_frequency / 1000000 % 1000,
 | 
					            frequency / 1000000 % 1000,
 | 
				
			||||||
            model->real_frequency / 1000 % 1000);
 | 
					            frequency / 10000 % 100);
 | 
				
			||||||
        canvas_draw_str(canvas, 60, 61, buffer);
 | 
					        canvas_draw_str(canvas, 40, 62, buffer);
 | 
				
			||||||
        elements_button_left(canvas, "Config");
 | 
					        canvas_draw_str(canvas, 75, 62, "AM");
 | 
				
			||||||
 | 
					        subghz_history_get_text_space_left(model->history, 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:
 | 
				
			||||||
@ -194,15 +205,27 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
 | 
				
			|||||||
        canvas_set_font(canvas, FontPrimary);
 | 
					        canvas_set_font(canvas, FontPrimary);
 | 
				
			||||||
        canvas_draw_str(canvas, 63, 40, "Scanning...");
 | 
					        canvas_draw_str(canvas, 63, 40, "Scanning...");
 | 
				
			||||||
        canvas_set_color(canvas, ColorBlack);
 | 
					        canvas_set_color(canvas, ColorBlack);
 | 
				
			||||||
        canvas_set_font(canvas, FontPrimary);
 | 
					        canvas_set_font(canvas, FontSecondary);
 | 
				
			||||||
 | 
					        elements_button_left(canvas, "Conf");
 | 
				
			||||||
 | 
					        canvas_invert_color(canvas);
 | 
				
			||||||
 | 
					        canvas_draw_box(canvas, 38, 52, 10, 10);
 | 
				
			||||||
 | 
					        canvas_invert_color(canvas);
 | 
				
			||||||
 | 
					        if((model->real_frequency / 1000 % 10) > 4) {
 | 
				
			||||||
 | 
					            frequency = model->real_frequency + 10000;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            frequency = model->real_frequency;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        snprintf(
 | 
					        snprintf(
 | 
				
			||||||
            buffer,
 | 
					            buffer,
 | 
				
			||||||
            sizeof(buffer),
 | 
					            sizeof(buffer),
 | 
				
			||||||
            "%03ld.%03ld  OOK",
 | 
					            "%03ld.%02ld",
 | 
				
			||||||
            model->real_frequency / 1000000 % 1000,
 | 
					            frequency / 1000000 % 1000,
 | 
				
			||||||
            model->real_frequency / 1000 % 1000);
 | 
					            frequency / 10000 % 100);
 | 
				
			||||||
        canvas_draw_str(canvas, 60, 61, buffer);
 | 
					        canvas_draw_str(canvas, 40, 62, buffer);
 | 
				
			||||||
        elements_button_left(canvas, "Config");
 | 
					        canvas_draw_str(canvas, 75, 62, "AM");
 | 
				
			||||||
 | 
					        subghz_history_get_text_space_left(model->history, str_buff);
 | 
				
			||||||
 | 
					        canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
 | 
				
			||||||
 | 
					        canvas_draw_line(canvas, 48, 51, 125, 51);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case ReceiverSceneConfig:
 | 
					    case ReceiverSceneConfig:
 | 
				
			||||||
@ -264,6 +287,14 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
 | 
				
			|||||||
    switch(scene) {
 | 
					    switch(scene) {
 | 
				
			||||||
    case ReceiverSceneMain:
 | 
					    case ReceiverSceneMain:
 | 
				
			||||||
        if(event->key == InputKeyBack) {
 | 
					        if(event->key == InputKeyBack) {
 | 
				
			||||||
 | 
					            with_view_model(
 | 
				
			||||||
 | 
					                subghz_receiver->view, (SubghzReceiverModel * model) {
 | 
				
			||||||
 | 
					                    model->idx = 0;
 | 
				
			||||||
 | 
					                    model->list_offset = 0;
 | 
				
			||||||
 | 
					                    model->history_item = 0;
 | 
				
			||||||
 | 
					                    subghz_history_clean(model->history);
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        } else if(event->key == InputKeyUp) {
 | 
					        } else if(event->key == InputKeyUp) {
 | 
				
			||||||
            with_view_model(
 | 
					            with_view_model(
 | 
				
			||||||
@ -456,32 +487,41 @@ static void subghz_receiver_timer_callback(void* context) {
 | 
				
			|||||||
    SubghzReceiver* subghz_receiver = context;
 | 
					    SubghzReceiver* subghz_receiver = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch(subghz_receiver->hopper_state) {
 | 
					    switch(subghz_receiver->hopper_state) {
 | 
				
			||||||
    case SubGhzHopperStateOFF:
 | 
					    case SubGhzHopperStatePause:
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SubGhzHopperStatePause:
 | 
					    case SubGhzHopperStateOFF:
 | 
				
			||||||
        osTimerStart(subghz_receiver->timer, 1024 / 10);
 | 
					        osTimerStop(subghz_receiver->timer);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					    case SubGhzHopperStateRSSITimeOut:
 | 
				
			||||||
 | 
					        if(subghz_receiver->hopper_timeout != 0) {
 | 
				
			||||||
 | 
					            subghz_receiver->hopper_timeout--;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    float rssi = -127.0f;
 | 
					    float rssi = -127.0f;
 | 
				
			||||||
    with_view_model(
 | 
					    with_view_model(
 | 
				
			||||||
        subghz_receiver->view, (SubghzReceiverModel * model) {
 | 
					        subghz_receiver->view, (SubghzReceiverModel * model) {
 | 
				
			||||||
            // See RSSI Calculation timings in CC1101 17.3 RSSI
 | 
					            if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
 | 
				
			||||||
            rssi = furi_hal_subghz_get_rssi();
 | 
					                // See RSSI Calculation timings in CC1101 17.3 RSSI
 | 
				
			||||||
 | 
					                rssi = furi_hal_subghz_get_rssi();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Stay if RSSI is high enough
 | 
					                // Stay if RSSI is high enough
 | 
				
			||||||
            if(rssi > -90.0f) {
 | 
					                if(rssi > -90.0f) {
 | 
				
			||||||
                osTimerStart(subghz_receiver->timer, 1024 / 4);
 | 
					                    subghz_receiver->hopper_timeout = 10;
 | 
				
			||||||
                return false;
 | 
					                    subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                osTimerStart(subghz_receiver->timer, 1024 / 10);
 | 
					                subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Select next frequency
 | 
					            // Select next frequency
 | 
				
			||||||
            if(model->frequency < COUNT_FREQUNCY_SCANER - 1) {
 | 
					            if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
 | 
				
			||||||
                model->frequency++;
 | 
					                model->frequency++;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                model->frequency = 0;
 | 
					                model->frequency = 0;
 | 
				
			||||||
@ -491,7 +531,7 @@ static void subghz_receiver_timer_callback(void* context) {
 | 
				
			|||||||
            subghz_rx_end(subghz_receiver->worker);
 | 
					            subghz_rx_end(subghz_receiver->worker);
 | 
				
			||||||
            subghz_protocol_reset(subghz_receiver->protocol);
 | 
					            subghz_protocol_reset(subghz_receiver->protocol);
 | 
				
			||||||
            model->real_frequency =
 | 
					            model->real_frequency =
 | 
				
			||||||
                subghz_rx(subghz_receiver->worker, subghz_frequencies_scanner[model->frequency]);
 | 
					                subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -553,7 +593,7 @@ SubghzReceiver* subghz_receiver_alloc() {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subghz_receiver->timer =
 | 
					    subghz_receiver->timer =
 | 
				
			||||||
        osTimerNew(subghz_receiver_timer_callback, osTimerOnce, subghz_receiver, NULL);
 | 
					        osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
 | 
				
			||||||
    subghz_receiver->hopper_state = SubGhzHopperStateOFF;
 | 
					    subghz_receiver->hopper_state = SubGhzHopperStateOFF;
 | 
				
			||||||
    return subghz_receiver;
 | 
					    return subghz_receiver;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,9 +8,6 @@
 | 
				
			|||||||
#include <gui/elements.h>
 | 
					#include <gui/elements.h>
 | 
				
			||||||
#include <notification/notification-messages.h>
 | 
					#include <notification/notification-messages.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#include <assets_icons.h>
 | 
					 | 
				
			||||||
#include <gui/icon_i.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct SubghzTransmitter {
 | 
					struct SubghzTransmitter {
 | 
				
			||||||
    View* view;
 | 
					    View* view;
 | 
				
			||||||
    SubghzTransmitterCallback callback;
 | 
					    SubghzTransmitterCallback callback;
 | 
				
			||||||
@ -64,7 +61,7 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
 | 
				
			|||||||
    const uint8_t string_width = canvas_string_width(canvas, str);
 | 
					    const uint8_t string_width = canvas_string_width(canvas, str);
 | 
				
			||||||
    const Icon* icon = &I_ButtonCenter_7x7;
 | 
					    const Icon* icon = &I_ButtonCenter_7x7;
 | 
				
			||||||
    const uint8_t icon_offset = 3;
 | 
					    const uint8_t icon_offset = 3;
 | 
				
			||||||
    const uint8_t icon_width_with_offset = icon->width + icon_offset;
 | 
					    const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset;
 | 
				
			||||||
    const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
 | 
					    const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40;
 | 
					    const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@
 | 
				
			|||||||
#include <furi-hal-ibutton.h>
 | 
					#include <furi-hal-ibutton.h>
 | 
				
			||||||
#include <furi-hal-resources.h>
 | 
					#include <furi-hal-resources.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stm32wbxx_ll_tim.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LFRFID_READ_TIM htim1
 | 
					#define LFRFID_READ_TIM htim1
 | 
				
			||||||
#define LFRFID_READ_CHANNEL TIM_CHANNEL_1
 | 
					#define LFRFID_READ_CHANNEL TIM_CHANNEL_1
 | 
				
			||||||
#define LFRFID_EMULATE_TIM htim2
 | 
					#define LFRFID_EMULATE_TIM htim2
 | 
				
			||||||
@ -216,7 +218,11 @@ void furi_hal_rfid_tim_emulate_stop() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void furi_hal_rfid_tim_reset() {
 | 
					void furi_hal_rfid_tim_reset() {
 | 
				
			||||||
    HAL_TIM_Base_DeInit(&LFRFID_READ_TIM);
 | 
					    HAL_TIM_Base_DeInit(&LFRFID_READ_TIM);
 | 
				
			||||||
 | 
					    LL_TIM_DeInit(TIM1);
 | 
				
			||||||
 | 
					    LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_TIM1);
 | 
				
			||||||
    HAL_TIM_Base_DeInit(&LFRFID_EMULATE_TIM);
 | 
					    HAL_TIM_Base_DeInit(&LFRFID_EMULATE_TIM);
 | 
				
			||||||
 | 
					    LL_TIM_DeInit(TIM2);
 | 
				
			||||||
 | 
					    LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool furi_hal_rfid_is_tim_emulate(TIM_HandleTypeDef* hw) {
 | 
					bool furi_hal_rfid_is_tim_emulate(TIM_HandleTypeDef* hw) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user