Merge pull request #121 from derskythe/dev-master

SubGHz Frequency Analyzer sync with OFW
This commit is contained in:
MX 2022-10-19 23:38:05 +03:00 committed by GitHub
commit e56f97245b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 285 additions and 177 deletions

View file

@ -72,6 +72,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
.frequency_coarse = 0, .rssi_coarse = 0, .frequency_fine = 0, .rssi_fine = 0};
float rssi = 0;
uint32_t frequency = 0;
float rssi_temp = 0;
uint32_t frequency_temp = 0;
CC1101Status status;
//Start CC1101
@ -195,6 +197,9 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
TAG, "=:%lu:%f", frequency_rssi.frequency_fine, (double)frequency_rssi.rssi_fine);
instance->sample_hold_counter = 20;
rssi_temp = frequency_rssi.rssi_fine;
frequency_temp = frequency_rssi.frequency_fine;
if(instance->filVal) {
frequency_rssi.frequency_fine =
subghz_frequency_analyzer_worker_expRunningAverageAdaptive(
@ -203,7 +208,10 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
// Deliver callback
if(instance->pair_callback) {
instance->pair_callback(
instance->context, frequency_rssi.frequency_fine, frequency_rssi.rssi_fine);
instance->context,
frequency_rssi.frequency_fine,
frequency_rssi.rssi_fine,
true);
}
} else if( // Deliver results coarse
(frequency_rssi.rssi_coarse > instance->trigger_level) &&
@ -215,6 +223,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
(double)frequency_rssi.rssi_coarse);
instance->sample_hold_counter = 20;
rssi_temp = frequency_rssi.rssi_coarse;
frequency_temp = frequency_rssi.frequency_coarse;
if(instance->filVal) {
frequency_rssi.frequency_coarse =
subghz_frequency_analyzer_worker_expRunningAverageAdaptive(
@ -225,14 +235,22 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
instance->pair_callback(
instance->context,
frequency_rssi.frequency_coarse,
frequency_rssi.rssi_coarse);
frequency_rssi.rssi_coarse,
true);
}
} else {
if(instance->sample_hold_counter > 0) {
instance->sample_hold_counter--;
if(instance->sample_hold_counter == 18) {
if(instance->pair_callback) {
instance->pair_callback(
instance->context, frequency_temp, rssi_temp, false);
}
}
} else {
instance->filVal = 0;
if(instance->pair_callback) instance->pair_callback(instance->context, 0, 0);
if(instance->pair_callback)
instance->pair_callback(instance->context, 0, 0, false);
}
}
}

View file

@ -5,8 +5,11 @@
typedef struct SubGhzFrequencyAnalyzerWorker SubGhzFrequencyAnalyzerWorker;
typedef void (
*SubGhzFrequencyAnalyzerWorkerPairCallback)(void* context, uint32_t frequency, float rssi);
typedef void (*SubGhzFrequencyAnalyzerWorkerPairCallback)(
void* context,
uint32_t frequency,
float rssi,
bool signal);
typedef struct {
uint32_t frequency_coarse;

View file

@ -1,8 +1,20 @@
#include "../subghz_i.h"
#include "../views/subghz_frequency_analyzer.h"
#include <dolphin/dolphin.h>
#define TAG "SubGhzSceneFrequencyAnalyzer"
static const NotificationSequence sequence_saved = {
&message_blink_stop,
&message_blue_0,
&message_green_255,
&message_red_0,
&message_vibro_on,
&message_delay_100,
&message_vibro_off,
NULL,
};
void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) {
furi_assert(context);
SubGhz* subghz = context;
@ -24,7 +36,28 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) {
bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventViewReceiverOK) {
if(event.event == SubGhzCustomEventSceneAnalyzerLock) {
notification_message(subghz->notifications, &sequence_set_green_255);
switch(subghz_frequency_analyzer_feedback_level(
subghz->subghz_frequency_analyzer,
SubGHzFrequencyAnalyzerFeedbackLevelAll,
false)) {
case SubGHzFrequencyAnalyzerFeedbackLevelAll:
notification_message(subghz->notifications, &sequence_success);
break;
case SubGHzFrequencyAnalyzerFeedbackLevelVibro:
notification_message(subghz->notifications, &sequence_single_vibro);
break;
case SubGHzFrequencyAnalyzerFeedbackLevelMute:
break;
}
notification_message(subghz->notifications, &sequence_display_backlight_on);
return true;
} else if(event.event == SubGhzCustomEventSceneAnalyzerUnlock) {
notification_message(subghz->notifications, &sequence_reset_rgb);
return true;
} else if(event.event == SubGhzCustomEventViewReceiverOK) {
notification_message(subghz->notifications, &sequence_saved);
uint32_t frequency =
subghz_frequency_analyzer_get_frequency_to_save(subghz->subghz_frequency_analyzer);
if(frequency > 0) {

View file

@ -15,57 +15,9 @@
#define RSSI_MIN -97
#define RSSI_MAX -60
#define RSSI_SCALE 2
#define RSSI_SCALE 2.5
#define TRIGGER_STEP 1
static const NotificationSequence sequence_hw_blink = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_hw_blink_stop = {
&message_blink_stop,
NULL,
};
static const NotificationSequence sequence_saved = {
&message_blink_stop,
&message_blue_0,
&message_green_255,
&message_red_0,
&message_vibro_on,
&message_delay_100,
&message_vibro_off,
NULL,
};
static const NotificationSequence sequence_frequency = {
&message_display_backlight_on,
&message_green_255,
&message_vibro_on,
&message_delay_100,
&message_green_0,
&message_blue_255,
&message_vibro_off,
&message_delay_100,
&message_blue_0,
&message_green_255,
&message_vibro_on,
&message_delay_100,
&message_green_0,
&message_vibro_off,
NULL,
};
//static const NotificationSequence sequence_not_saved = {
// &message_blink_stop,
// &message_green_255,
// &message_blue_255,
// &message_red_255,
// NULL,
//};
#define MAX_HISTORY 4
static const uint32_t subghz_frequency_list[] = {
300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000,
@ -85,21 +37,26 @@ struct SubGhzFrequencyAnalyzer {
SubGhzFrequencyAnalyzerCallback callback;
void* context;
bool locked;
uint8_t feedback_level; // 0 - no feedback, 1 - vibro only, 2 - vibro and sound
SubGHzFrequencyAnalyzerFeedbackLevel
feedback_level; // 0 - no feedback, 1 - vibro only, 2 - vibro and sound
float rssi_last;
uint32_t frequency_last;
uint32_t frequency_last_vis;
NotificationApp* notifications;
uint8_t selected_index;
uint8_t max_index;
bool show_frame;
};
typedef struct {
uint32_t frequency;
uint32_t frequency_last;
uint32_t frequency_to_save;
float rssi;
uint32_t history_frequency[MAX_HISTORY];
bool signal;
float rssi_last;
float trigger;
uint8_t feedback_level;
SubGHzFrequencyAnalyzerFeedbackLevel feedback_level;
uint8_t selected_index;
uint8_t max_index;
bool show_frame;
} SubGhzFrequencyAnalyzerModel;
void subghz_frequency_analyzer_set_callback(
@ -121,7 +78,9 @@ void subghz_frequency_analyzer_draw_rssi(
uint8_t y) {
// Current RSSI
if(rssi) {
if(rssi > RSSI_MAX) rssi = RSSI_MAX;
if(rssi > RSSI_MAX) {
rssi = RSSI_MAX;
}
rssi = (rssi - RSSI_MIN) / RSSI_SCALE;
uint8_t column_number = 0;
for(size_t i = 0; i <= (uint8_t)rssi; i++) {
@ -134,7 +93,9 @@ void subghz_frequency_analyzer_draw_rssi(
// Last RSSI
if(rssi_last) {
if(rssi_last > RSSI_MAX) rssi_last = RSSI_MAX;
if(rssi_last > RSSI_MAX) {
rssi_last = RSSI_MAX;
}
int max_x = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) * 2;
//if(!(max_x % 8)) max_x -= 2;
int max_h = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) + 4;
@ -151,19 +112,62 @@ void subghz_frequency_analyzer_draw_rssi(
canvas_draw_line(canvas, x, y + 3, x + (RSSI_MAX - RSSI_MIN) * 2 / RSSI_SCALE, y + 3);
}
static void subghz_frequency_analyzer_history_frequency_draw(
Canvas* canvas,
SubGhzFrequencyAnalyzerModel* model) {
char buffer[64];
const uint8_t x1 = 2;
const uint8_t x2 = 66;
const uint8_t y = 37;
canvas_set_font(canvas, FontSecondary);
uint8_t line = 0;
bool show_frame = model->show_frame && model->max_index > 0;
for(uint8_t i = 0; i < MAX_HISTORY; i++) {
uint8_t current_x;
uint8_t current_y = y + line * 11;
if(i % 2 == 0) {
current_x = x1;
} else {
current_x = x2;
line++;
}
if(model->history_frequency[i]) {
snprintf(
buffer,
sizeof(buffer),
"%03ld.%03ld",
model->history_frequency[i] / 1000000 % 1000,
model->history_frequency[i] / 1000 % 1000);
canvas_draw_str(canvas, current_x, current_y, buffer);
} else {
canvas_draw_str(canvas, current_x, current_y, "---.---");
}
canvas_draw_str(canvas, current_x + 41, current_y, "MHz");
if(show_frame && i == model->selected_index) {
elements_frame(canvas, current_x - 2, current_y - 9, 63, 11);
}
}
}
void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) {
char buffer[64];
// Title
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 20, 8, "Frequency Analyzer");
canvas_draw_str(canvas, 20, 7, "Frequency Analyzer");
// RSSI
canvas_draw_str(canvas, 33, 62, "RSSI");
subghz_frequency_analyzer_draw_rssi(
canvas, model->rssi, model->rssi_last, model->trigger, 57, 58);
// Last detected frequency
subghz_frequency_analyzer_history_frequency_draw(canvas, model);
// Frequency
canvas_set_font(canvas, FontBigNumbers);
snprintf(
@ -172,39 +176,38 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel
"%03ld.%03ld",
model->frequency / 1000000 % 1000,
model->frequency / 1000 % 1000);
canvas_draw_str(canvas, 8, 30, buffer);
canvas_draw_icon(canvas, 96, 19, &I_MHz_25x11);
// Last detected frequency
canvas_set_font(canvas, FontSecondary);
if(model->frequency_last) {
snprintf(
buffer,
sizeof(buffer),
"Last: %03ld.%03ld MHz",
model->frequency_last / 1000000 % 1000,
model->frequency_last / 1000 % 1000);
} else {
strcpy(buffer, "Last: ---.--- MHz");
}
canvas_draw_str(canvas, 9, 42, buffer);
switch(model->feedback_level) {
case 2:
canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Volup_8x6);
break;
case 1:
canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Voldwn_6x6);
break;
case 0:
canvas_draw_icon(canvas, 128 - 8 - 1, 1, &I_Voldwn_6x6);
if(model->signal) {
canvas_draw_box(canvas, 4, 10, 121, 19);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 128 - 2 - 1 - 2, 1, 2, 6);
} else {
// TODO: Disable this
//canvas_draw_box(canvas, 4, 11, 121, 19);
//canvas_set_color(canvas, ColorWhite);
}
canvas_draw_str(canvas, 8, 26, buffer);
canvas_draw_icon(canvas, 96, 15, &I_MHz_25x11);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
const uint8_t icon_x = 119;
switch(model->feedback_level) {
case SubGHzFrequencyAnalyzerFeedbackLevelAll:
canvas_draw_icon(canvas, icon_x, 1, &I_Volup_8x6);
break;
case SubGHzFrequencyAnalyzerFeedbackLevelVibro:
canvas_draw_icon(canvas, icon_x, 1, &I_Voldwn_6x6);
break;
case SubGHzFrequencyAnalyzerFeedbackLevelMute:
canvas_draw_icon(canvas, icon_x, 1, &I_Voldwn_6x6);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 123, 1, 2, 6);
canvas_set_color(canvas, ColorBlack);
break;
}
// Buttons hint
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "T-");
elements_button_right(canvas, "T+");
}
@ -242,7 +245,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
bool need_redraw = false;
if(event->key == InputKeyBack) return false;
if(event->key == InputKeyBack) {
return false;
}
if(((event->type == InputTypePress) || (event->type == InputTypeRepeat)) &&
((event->key == InputKeyLeft) || (event->key == InputKeyRight))) {
@ -251,42 +256,51 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
switch(event->key) {
case InputKeyLeft:
trigger_level -= TRIGGER_STEP;
if(trigger_level < RSSI_MIN) trigger_level = RSSI_MIN;
if(trigger_level < RSSI_MIN) {
trigger_level = RSSI_MIN;
}
break;
default:
case InputKeyRight:
trigger_level += TRIGGER_STEP;
if(trigger_level > RSSI_MAX) trigger_level = RSSI_MAX;
if(trigger_level > RSSI_MAX) {
trigger_level = RSSI_MAX;
}
break;
}
subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, trigger_level);
FURI_LOG_I(TAG, "trigger = %.1f", (double)trigger_level);
need_redraw = true;
}
if(event->type == InputTypePress && event->key == InputKeyDown) {
} else if(event->type == InputTypePress && event->key == InputKeyDown) {
if(instance->feedback_level == 0) {
instance->feedback_level = 2;
} else {
instance->feedback_level--;
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "feedback_level = %d", instance->feedback_level);
#endif
need_redraw = true;
} else if(
((event->type == InputTypePress) || (event->type == InputTypeRepeat)) &&
event->key == InputKeyUp) {
instance->show_frame = instance->max_index > 0;
if(instance->show_frame) {
instance->selected_index = (instance->selected_index + 1) % instance->max_index;
need_redraw = true;
}
if(event->key == InputKeyOk) {
} else if(event->key == InputKeyOk) {
need_redraw = true;
bool updated = false;
uint32_t frequency_to_save = 0;
with_view_model(
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
frequency_to_save = model->frequency_to_save;
if(model->show_frame) {
uint32_t prev_freq_to_save = model->frequency_to_save;
uint32_t frequency_candidate = 0;
if(model->frequency != 0) {
frequency_candidate = model->frequency;
} else if(model->frequency_last != 0) {
frequency_candidate = model->frequency_last;
}
uint32_t frequency_candidate = model->history_frequency[model->selected_index];
if(frequency_candidate == 0 ||
!furi_hal_subghz_is_frequency_valid(frequency_candidate) ||
prev_freq_to_save == frequency_candidate) {
@ -294,7 +308,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
} else {
frequency_candidate = subghz_frequency_find_correct(frequency_candidate);
}
if(frequency_candidate > 0 && frequency_candidate != model->frequency_to_save) {
if(frequency_candidate > 0 &&
frequency_candidate != model->frequency_to_save) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
@ -303,10 +318,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
frequency_candidate);
#endif
model->frequency_to_save = frequency_candidate;
notification_message(instance->notifications, &sequence_saved);
notification_message(instance->notifications, &sequence_hw_blink);
updated = true;
}
}
},
true);
@ -324,13 +338,10 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
}
// First device receive short, then when user release button we get long
if(event->type == InputTypeLong) {
if(event->type == InputTypeLong && frequency_to_save > 0) {
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Long press!");
#endif
// Stop blinking
notification_message(instance->notifications, &sequence_hw_blink_stop);
// Stop worker
if(subghz_frequency_analyzer_worker_is_running(instance->worker)) {
subghz_frequency_analyzer_worker_stop(instance->worker);
@ -346,10 +357,12 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
SubGhzFrequencyAnalyzerModel * model,
{
model->rssi_last = instance->rssi_last;
model->frequency_last = instance->frequency_last;
model->trigger =
subghz_frequency_analyzer_worker_get_trigger_level(instance->worker);
model->feedback_level = instance->feedback_level;
model->max_index = instance->max_index;
model->show_frame = instance->show_frame;
model->selected_index = instance->selected_index;
},
true);
}
@ -369,43 +382,76 @@ uint32_t round_int(uint32_t value, uint8_t n) {
return value;
}
void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) {
furi_assert(context);
void subghz_frequency_analyzer_pair_callback(
void* context,
uint32_t frequency,
float rssi,
bool signal) {
SubGhzFrequencyAnalyzer* instance = context;
if((rssi == 0.f) && (instance->locked)) {
notification_message(instance->notifications, &sequence_hw_blink);
instance->frequency_last_vis = instance->frequency_last;
if(instance->callback) {
instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context);
}
//update history
instance->show_frame = true;
uint8_t max_index = instance->max_index;
with_view_model(
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
bool in_array = false;
uint32_t normal_frequency = subghz_frequency_find_correct(model->frequency);
for(size_t i = 0; i < MAX_HISTORY; i++) {
if(model->history_frequency[i] == normal_frequency) {
in_array = true;
if(i > 0) {
size_t offset = 0;
for(size_t j = MAX_HISTORY - 1; j > 0; j--) {
if(j == i) {
offset++;
}
model->history_frequency[j] = model->history_frequency[j - offset];
}
model->history_frequency[0] = normal_frequency;
}
if((rssi != 0.f) && (frequency != 0)) {
// Threre is some signal
break;
}
}
if(!in_array) {
model->history_frequency[3] = model->history_frequency[2];
model->history_frequency[2] = model->history_frequency[1];
model->history_frequency[1] = model->history_frequency[0];
model->history_frequency[0] = normal_frequency;
}
if(max_index < MAX_HISTORY) {
for(size_t i = 0; i < MAX_HISTORY; i++) {
if(model->history_frequency[i] > 0) {
max_index = i + 1;
}
}
}
},
false);
instance->max_index = max_index;
} else if((rssi != 0.f) && (!instance->locked)) {
// There is some signal
FURI_LOG_I(TAG, "rssi = %.2f, frequency = %ld Hz", (double)rssi, frequency);
frequency = round_int(frequency, 3); // Round 299999990Hz to 300000000Hz
if(!instance->locked) {
// Triggered!
instance->rssi_last = rssi;
notification_message(instance->notifications, &sequence_hw_blink_stop);
switch(instance->feedback_level) {
case 1: // 1 - only vibro
notification_message(instance->notifications, &sequence_frequency);
break;
case 2: // 2 - vibro and beep
notification_message(instance->notifications, &sequence_success);
break;
default: // 0 - no feedback
notification_message(instance->notifications, &sequence_display_backlight_on);
break;
if(instance->callback) {
instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context);
}
}
FURI_LOG_D(TAG, "triggered");
}
// Update values
if(rssi >= instance->rssi_last) {
if(rssi >= instance->rssi_last && (frequency != 0)) {
instance->rssi_last = rssi;
instance->frequency_last = frequency;
}
}
instance->locked = (rssi != 0.f);
@ -416,9 +462,12 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency,
model->rssi = rssi;
model->rssi_last = instance->rssi_last;
model->frequency = frequency;
model->frequency_last = instance->frequency_last_vis;
model->signal = signal;
model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker);
model->feedback_level = instance->feedback_level;
model->max_index = instance->max_index;
model->show_frame = instance->show_frame;
model->selected_index = instance->selected_index;
},
true);
}
@ -427,10 +476,6 @@ void subghz_frequency_analyzer_enter(void* context) {
furi_assert(context);
SubGhzFrequencyAnalyzer* instance = context;
// Notifications
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
notification_message(instance->notifications, &sequence_hw_blink);
//Start worker
instance->worker = subghz_frequency_analyzer_worker_alloc(instance->context);
@ -442,18 +487,25 @@ void subghz_frequency_analyzer_enter(void* context) {
subghz_frequency_analyzer_worker_start(instance->worker);
instance->rssi_last = 0;
instance->frequency_last = 0;
instance->frequency_last_vis = 0;
instance->selected_index = 0;
instance->max_index = 0;
instance->show_frame = false;
subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, RSSI_MIN);
with_view_model(
instance->view,
SubGhzFrequencyAnalyzerModel * model,
{
model->selected_index = 0;
model->max_index = 0;
model->show_frame = false;
model->rssi = 0;
model->rssi_last = 0;
model->frequency = 0;
model->frequency_last = 0;
model->history_frequency[3] = 0;
model->history_frequency[2] = 0;
model->history_frequency[1] = 0;
model->history_frequency[0] = 0;
model->frequency_to_save = 0;
model->trigger = RSSI_MIN;
},
@ -464,9 +516,6 @@ void subghz_frequency_analyzer_exit(void* context) {
furi_assert(context);
SubGhzFrequencyAnalyzer* instance = context;
// Stop blinking
notification_message(instance->notifications, &sequence_hw_blink_stop);
// Stop worker
if(subghz_frequency_analyzer_worker_is_running(instance->worker)) {
subghz_frequency_analyzer_worker_stop(instance->worker);
@ -478,7 +527,6 @@ void subghz_frequency_analyzer_exit(void* context) {
SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer));
furi_assert(instance);
instance->feedback_level = 2;
@ -519,9 +567,9 @@ uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer
return frequency;
}
uint8_t subghz_frequency_analyzer_feedback_level(
SubGHzFrequencyAnalyzerFeedbackLevel subghz_frequency_analyzer_feedback_level(
SubGhzFrequencyAnalyzer* instance,
uint8_t level,
SubGHzFrequencyAnalyzerFeedbackLevel level,
bool update) {
furi_assert(instance);
if(update) {

View file

@ -3,6 +3,12 @@
#include <gui/view.h>
#include "../helpers/subghz_custom_event.h"
typedef enum {
SubGHzFrequencyAnalyzerFeedbackLevelAll,
SubGHzFrequencyAnalyzerFeedbackLevelVibro,
SubGHzFrequencyAnalyzerFeedbackLevelMute
} SubGHzFrequencyAnalyzerFeedbackLevel;
typedef struct SubGhzFrequencyAnalyzer SubGhzFrequencyAnalyzer;
typedef void (*SubGhzFrequencyAnalyzerCallback)(SubGhzCustomEvent event, void* context);
@ -20,7 +26,7 @@ View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* subghz_static)
uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer* instance);
uint8_t subghz_frequency_analyzer_feedback_level(
SubGHzFrequencyAnalyzerFeedbackLevel subghz_frequency_analyzer_feedback_level(
SubGhzFrequencyAnalyzer* instance,
uint8_t level,
SubGHzFrequencyAnalyzerFeedbackLevel level,
bool update);