[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:
Skorpionm 2021-08-31 00:05:09 +04:00 committed by GitHub
parent 8b9210704a
commit 6f7bcdf9a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 147 additions and 366 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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
View 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) {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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(

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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) {