[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;
|
||||
void* back_context;
|
||||
|
||||
uint8_t ongoing_input_events_count;
|
||||
};
|
||||
|
||||
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) {
|
||||
while(view_holder->ongoing_input_events_count > 0) osDelay(1);
|
||||
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) {
|
||||
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;
|
||||
|
||||
if(view_holder->view) {
|
||||
|
@ -35,11 +35,6 @@ void view_set_previous_callback(View* view, ViewNavigationCallback 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) {
|
||||
furi_assert(view);
|
||||
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) {
|
||||
furi_assert(view);
|
||||
if(view->enter_callback) view->enter_callback(view->context);
|
||||
|
@ -14,11 +14,6 @@ extern "C" {
|
||||
#define VIEW_NONE 0xFFFFFFFF
|
||||
/* Ignore navigation event */
|
||||
#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 {
|
||||
ViewOrientationHorizontal,
|
||||
@ -119,12 +114,6 @@ void view_set_custom_callback(View* view, ViewCustomCallback 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
|
||||
* @param view, pointer to View
|
||||
* @param callback, callback
|
||||
|
37
applications/gui/view_dispatcher.c
Executable file → Normal file
37
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -153,13 +165,16 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
|
||||
if(view_id == VIEW_NONE) {
|
||||
view_dispatcher_set_current_view(view_dispatcher, NULL);
|
||||
} else if(view_id == VIEW_IGNORE) {
|
||||
} else if(view_id == VIEW_DESTROY) {
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
} else {
|
||||
View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
|
||||
furi_check(view_pp != NULL);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void view_dispatcher_attach_to_gui(
|
||||
@ -202,6 +217,16 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) {
|
||||
}
|
||||
|
||||
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;
|
||||
if(view_dispatcher->current_view) {
|
||||
is_consumed = view_input(view_dispatcher->current_view, event);
|
||||
@ -219,13 +244,17 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
view_id = view_next(view_dispatcher->current_view);
|
||||
}
|
||||
if(!is_consumed) {
|
||||
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) {
|
||||
|
@ -113,6 +113,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
|
||||
/** Switch to View
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @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);
|
||||
|
||||
|
@ -14,7 +14,12 @@ struct ViewDispatcher {
|
||||
Gui* gui;
|
||||
ViewPort* view_port;
|
||||
ViewDict_t views;
|
||||
|
||||
View* current_view;
|
||||
|
||||
View* delayed_next_view;
|
||||
uint8_t ongoing_input_events_count;
|
||||
|
||||
ViewDispatcherCustomEventCallback custom_event_callback;
|
||||
ViewDispatcherNavigationEventCallback navigation_event_callback;
|
||||
ViewDispatcherTickEventCallback tick_event_callback;
|
||||
|
@ -15,7 +15,6 @@ struct View {
|
||||
|
||||
ViewModelType model_type;
|
||||
ViewNavigationCallback previous_callback;
|
||||
ViewNavigationCallback next_callback;
|
||||
ViewCallback enter_callback;
|
||||
ViewCallback exit_callback;
|
||||
ViewOrientation orientation;
|
||||
@ -42,9 +41,6 @@ bool view_custom(View* view, uint32_t event);
|
||||
/* Previous Callback for View dispatcher */
|
||||
uint32_t view_previous(View* view);
|
||||
|
||||
/* Next Callback for View dispatcher */
|
||||
uint32_t view_next(View* view);
|
||||
|
||||
/* Enter Callback for View dispatcher */
|
||||
void view_enter(View* view);
|
||||
|
||||
|
@ -131,9 +131,6 @@ int32_t input_srv() {
|
||||
// Common state info
|
||||
InputEvent event;
|
||||
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
|
||||
if(state) {
|
||||
@ -146,6 +143,10 @@ int32_t input_srv() {
|
||||
}
|
||||
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, analyze, Analyze)
|
||||
ADD_SCENE(subghz, receiver, Receiver)
|
||||
ADD_SCENE(subghz, save_name, SaveName)
|
||||
ADD_SCENE(subghz, save_success, SaveSuccess)
|
||||
|
@ -25,9 +25,13 @@ const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent e
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
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, SubGhzSceneReceiver)) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexAnalyze,
|
||||
SubmenuIndexRead,
|
||||
SubmenuIndexSaved,
|
||||
SubmenuIndexTest,
|
||||
@ -18,12 +17,6 @@ const void subghz_scene_start_on_enter(void* context) {
|
||||
if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) {
|
||||
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
|
||||
}
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Analyze",
|
||||
SubmenuIndexAnalyze,
|
||||
subghz_scene_start_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
|
||||
submenu_add_item(
|
||||
@ -47,12 +40,7 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexAnalyze) {
|
||||
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) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
|
||||
|
@ -70,13 +70,6 @@ SubGhz* subghz_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
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
|
||||
subghz->subghz_receiver = subghz_receiver_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@ -159,10 +152,6 @@ void subghz_free(SubGhz* subghz) {
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
|
||||
subghz_test_static_free(subghz->subghz_test_static);
|
||||
|
||||
// Analyze
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze);
|
||||
subghz_analyze_free(subghz->subghz_analyze);
|
||||
|
||||
// Receiver
|
||||
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);
|
||||
subghz_receiver_free(subghz->subghz_receiver);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#define SUBGHZ_HISTORY_MAX 20
|
||||
#define SUBGHZ_HISTORY_MAX 50
|
||||
|
||||
typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
|
||||
|
||||
@ -88,7 +88,10 @@ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, u
|
||||
instance->data.param1 = instance->history[idx].te;
|
||||
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) {
|
||||
if(instance->history[idx].code_count_bit < 33) {
|
||||
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);
|
||||
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_space_left(SubGhzHistory* instance, string_t output);
|
||||
void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
|
||||
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "subghz.h"
|
||||
#include "views/subghz_analyze.h"
|
||||
#include "views/subghz_receiver.h"
|
||||
#include "views/subghz_transmitter.h"
|
||||
|
||||
@ -59,7 +58,6 @@ struct SubGhz {
|
||||
char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
|
||||
uint8_t state_notifications;
|
||||
|
||||
SubghzAnalyze* subghz_analyze;
|
||||
SubghzReceiver* subghz_receiver;
|
||||
SubghzTransmitter* subghz_transmitter;
|
||||
|
||||
@ -71,7 +69,6 @@ struct SubGhz {
|
||||
typedef enum {
|
||||
SubGhzViewMenu,
|
||||
|
||||
SubGhzViewAnalyze,
|
||||
SubGhzViewDialogEx,
|
||||
SubGhzViewReceiver,
|
||||
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 MENU_ITEMS 4
|
||||
|
||||
#define COUNT_FREQUNCY_SCANER 3
|
||||
const uint32_t subghz_frequencies_scanner[] = {
|
||||
#define COUNT_FREQUNCY_HOPPER 3
|
||||
const uint32_t subghz_frequencies_hopper[] = {
|
||||
/* 300 - 348 */
|
||||
315000000,
|
||||
/* 387 - 464 */
|
||||
@ -35,6 +35,7 @@ typedef enum {
|
||||
SubGhzHopperStateOFF,
|
||||
SubGhzHopperStatePause,
|
||||
SubGhzHopperStateRunnig,
|
||||
SubGhzHopperStateRSSITimeOut,
|
||||
} SubGhzHopperState;
|
||||
|
||||
static const Icon* ReceiverItemIcons[] = {
|
||||
@ -51,6 +52,7 @@ struct SubghzReceiver {
|
||||
SubGhzProtocol* protocol;
|
||||
osTimerId timer;
|
||||
SubGhzHopperState hopper_state;
|
||||
uint8_t hopper_timeout;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -62,8 +64,6 @@ typedef struct {
|
||||
uint8_t temp_frequency;
|
||||
uint32_t real_frequency;
|
||||
|
||||
uint8_t tab_idx;
|
||||
uint8_t menu_idx;
|
||||
uint16_t idx;
|
||||
uint16_t list_offset;
|
||||
uint16_t history_item;
|
||||
@ -146,6 +146,7 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
bool scrollbar = model->history_item > 4;
|
||||
string_t str_buff;
|
||||
char buffer[64];
|
||||
uint32_t frequency;
|
||||
string_init(str_buff);
|
||||
|
||||
canvas_clear(canvas);
|
||||
@ -174,15 +175,25 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
|
||||
}
|
||||
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(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%03ld.%03ld OOK",
|
||||
model->real_frequency / 1000000 % 1000,
|
||||
model->real_frequency / 1000 % 1000);
|
||||
canvas_draw_str(canvas, 60, 61, buffer);
|
||||
elements_button_left(canvas, "Config");
|
||||
"%03ld.%02ld",
|
||||
frequency / 1000000 % 1000,
|
||||
frequency / 10000 % 100);
|
||||
canvas_draw_str(canvas, 40, 62, buffer);
|
||||
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;
|
||||
|
||||
case ReceiverSceneStart:
|
||||
@ -194,15 +205,27 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 63, 40, "Scanning...");
|
||||
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(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%03ld.%03ld OOK",
|
||||
model->real_frequency / 1000000 % 1000,
|
||||
model->real_frequency / 1000 % 1000);
|
||||
canvas_draw_str(canvas, 60, 61, buffer);
|
||||
elements_button_left(canvas, "Config");
|
||||
"%03ld.%02ld",
|
||||
frequency / 1000000 % 1000,
|
||||
frequency / 10000 % 100);
|
||||
canvas_draw_str(canvas, 40, 62, buffer);
|
||||
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;
|
||||
|
||||
case ReceiverSceneConfig:
|
||||
@ -264,6 +287,14 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
|
||||
switch(scene) {
|
||||
case ReceiverSceneMain:
|
||||
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;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
with_view_model(
|
||||
@ -456,32 +487,41 @@ static void subghz_receiver_timer_callback(void* context) {
|
||||
SubghzReceiver* subghz_receiver = context;
|
||||
|
||||
switch(subghz_receiver->hopper_state) {
|
||||
case SubGhzHopperStateOFF:
|
||||
case SubGhzHopperStatePause:
|
||||
return;
|
||||
break;
|
||||
case SubGhzHopperStatePause:
|
||||
osTimerStart(subghz_receiver->timer, 1024 / 10);
|
||||
case SubGhzHopperStateOFF:
|
||||
osTimerStop(subghz_receiver->timer);
|
||||
return;
|
||||
break;
|
||||
case SubGhzHopperStateRSSITimeOut:
|
||||
if(subghz_receiver->hopper_timeout != 0) {
|
||||
subghz_receiver->hopper_timeout--;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
float rssi = -127.0f;
|
||||
with_view_model(
|
||||
subghz_receiver->view, (SubghzReceiverModel * model) {
|
||||
if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
||||
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
||||
rssi = furi_hal_subghz_get_rssi();
|
||||
|
||||
// Stay if RSSI is high enough
|
||||
if(rssi > -90.0f) {
|
||||
osTimerStart(subghz_receiver->timer, 1024 / 4);
|
||||
subghz_receiver->hopper_timeout = 10;
|
||||
subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
osTimerStart(subghz_receiver->timer, 1024 / 10);
|
||||
subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
|
||||
}
|
||||
|
||||
// Select next frequency
|
||||
if(model->frequency < COUNT_FREQUNCY_SCANER - 1) {
|
||||
if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
|
||||
model->frequency++;
|
||||
} else {
|
||||
model->frequency = 0;
|
||||
@ -491,7 +531,7 @@ static void subghz_receiver_timer_callback(void* context) {
|
||||
subghz_rx_end(subghz_receiver->worker);
|
||||
subghz_protocol_reset(subghz_receiver->protocol);
|
||||
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;
|
||||
});
|
||||
@ -553,7 +593,7 @@ SubghzReceiver* subghz_receiver_alloc() {
|
||||
});
|
||||
|
||||
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;
|
||||
return subghz_receiver;
|
||||
}
|
||||
|
@ -8,9 +8,6 @@
|
||||
#include <gui/elements.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
//#include <assets_icons.h>
|
||||
#include <gui/icon_i.h>
|
||||
|
||||
struct SubghzTransmitter {
|
||||
View* view;
|
||||
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 Icon* icon = &I_ButtonCenter_7x7;
|
||||
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 x = (canvas_width(canvas) - button_width) / 2 + 40;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <furi-hal-ibutton.h>
|
||||
#include <furi-hal-resources.h>
|
||||
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
|
||||
#define LFRFID_READ_TIM htim1
|
||||
#define LFRFID_READ_CHANNEL TIM_CHANNEL_1
|
||||
#define LFRFID_EMULATE_TIM htim2
|
||||
@ -216,7 +218,11 @@ void furi_hal_rfid_tim_emulate_stop() {
|
||||
|
||||
void furi_hal_rfid_tim_reset() {
|
||||
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);
|
||||
LL_TIM_DeInit(TIM2);
|
||||
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
||||
}
|
||||
|
||||
bool furi_hal_rfid_is_tim_emulate(TIM_HandleTypeDef* hw) {
|
||||
|
Loading…
Reference in New Issue
Block a user