mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-23 13:03:13 +00:00
New frequency analyzer
This commit is contained in:
parent
ac1a53dbf8
commit
53b5b7b9df
3 changed files with 187 additions and 42 deletions
|
@ -5,7 +5,7 @@
|
|||
|
||||
#define TAG "SubghzFrequencyAnalyzerWorker"
|
||||
|
||||
#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -95.0f
|
||||
#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -97.0f
|
||||
|
||||
static const uint8_t subghz_preset_ook_58khz[][2] = {
|
||||
{CC1101_MDMCFG4, 0b11110111}, // Rx BW filter is 58.035714kHz
|
||||
|
|
|
@ -17,16 +17,8 @@ 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 == SubGhzCustomEventSceneAnalyzerLock) {
|
||||
notification_message(subghz->notifications, &sequence_set_green_255);
|
||||
return true;
|
||||
} else if(event.event == SubGhzCustomEventSceneAnalyzerUnlock) {
|
||||
notification_message(subghz->notifications, &sequence_reset_rgb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,31 @@
|
|||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/elements.h>
|
||||
#include "../helpers/subghz_frequency_analyzer_worker.h"
|
||||
|
||||
#include <assets_icons.h>
|
||||
|
||||
#define TAG "frequency_analyzer"
|
||||
|
||||
#define RSSI_MIN -101
|
||||
#define RSSI_MAX -60
|
||||
#define RSSI_SCALE 2
|
||||
#define TRIGGER_STEP 1
|
||||
#define TRIGGER_MIN RSSI_MIN + RSSI_SCALE * 2
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SubGhzFrequencyAnalyzerStatusIDLE,
|
||||
} SubGhzFrequencyAnalyzerStatus;
|
||||
|
@ -20,11 +41,19 @@ struct SubGhzFrequencyAnalyzer {
|
|||
SubGhzFrequencyAnalyzerCallback callback;
|
||||
void* context;
|
||||
bool locked;
|
||||
float rssi_last;
|
||||
uint32_t frequency_last;
|
||||
float trigger;
|
||||
bool triggered;
|
||||
NotificationApp* notifications;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint32_t frequency_last;
|
||||
float rssi;
|
||||
float rssi_last;
|
||||
float trigger;
|
||||
} SubGhzFrequencyAnalyzerModel;
|
||||
|
||||
void subghz_frequency_analyzer_set_callback(
|
||||
|
@ -37,33 +66,64 @@ void subghz_frequency_analyzer_set_callback(
|
|||
subghz_frequency_analyzer->context = context;
|
||||
}
|
||||
|
||||
void subghz_frequency_analyzer_draw_rssi(Canvas* canvas, float rssi) {
|
||||
uint8_t x = 48;
|
||||
uint8_t y = 56;
|
||||
uint8_t column_number = 0;
|
||||
void subghz_frequency_analyzer_draw_rssi(
|
||||
Canvas* canvas,
|
||||
float rssi,
|
||||
float rssi_last,
|
||||
float trigger,
|
||||
uint8_t x,
|
||||
uint8_t y) {
|
||||
// Current RSSI
|
||||
if(rssi) {
|
||||
rssi = (rssi + 90) / 3;
|
||||
rssi = (rssi - RSSI_MIN) / RSSI_SCALE;
|
||||
if(rssi > 20) rssi = 20;
|
||||
uint8_t column_number = 0;
|
||||
for(size_t i = 1; i < (uint8_t)rssi; i++) {
|
||||
if(i > 20) break;
|
||||
if(i % 4) {
|
||||
column_number++;
|
||||
canvas_draw_box(canvas, x + 2 * i, y - column_number, 2, 4 + column_number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last RSSI
|
||||
if(rssi_last) {
|
||||
int max_x = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE - 1) * 2;
|
||||
//if(!(max_x % 8)) max_x -= 2;
|
||||
int max_h = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE - 1) + 4;
|
||||
max_h -= (max_h / 4) + 3;
|
||||
if(max_x > 38) max_h = 38;
|
||||
if(max_h > 19) max_h = 19;
|
||||
if(max_x >= 0 && max_h > 0) {
|
||||
canvas_draw_line(canvas, x + max_x + 1, y - max_h, x + max_x + 1, y + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger cursor
|
||||
if(trigger >= RSSI_MIN + RSSI_SCALE * 2) {
|
||||
trigger = (trigger - RSSI_MIN) / RSSI_SCALE;
|
||||
uint8_t tr_x = x + 2 * trigger - 2;
|
||||
canvas_draw_dot(canvas, tr_x, y + 4);
|
||||
canvas_draw_line(canvas, tr_x - 1, y + 5, tr_x + 1, y + 5);
|
||||
}
|
||||
|
||||
canvas_draw_line(canvas, x + 2, y + 3, x + 39, y + 3);
|
||||
}
|
||||
|
||||
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, 28, 60, "RSSI");
|
||||
subghz_frequency_analyzer_draw_rssi(canvas, model->rssi);
|
||||
// RSSI
|
||||
canvas_draw_str(canvas, 33, 62, "RSSI");
|
||||
subghz_frequency_analyzer_draw_rssi(
|
||||
canvas, model->rssi, model->rssi_last, model->trigger, 55, 58);
|
||||
|
||||
//Frequency
|
||||
// Frequency
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
snprintf(
|
||||
buffer,
|
||||
|
@ -71,29 +131,113 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel
|
|||
"%03ld.%03ld",
|
||||
model->frequency / 1000000 % 1000,
|
||||
model->frequency / 1000 % 1000);
|
||||
canvas_draw_str(canvas, 8, 35, buffer);
|
||||
canvas_draw_icon(canvas, 96, 24, &I_MHz_25x11);
|
||||
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);
|
||||
|
||||
// Buttons hint
|
||||
elements_button_left(canvas, "T-");
|
||||
elements_button_right(canvas, "T+");
|
||||
}
|
||||
|
||||
bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
bool need_redraw = false;
|
||||
|
||||
if(event->key == InputKeyBack) return false;
|
||||
|
||||
if(((event->type == InputTypePress) || (event->type == InputTypeRepeat)) &&
|
||||
((event->key == InputKeyLeft) || (event->key == InputKeyRight))) {
|
||||
// Trigger setup
|
||||
switch(event->key) {
|
||||
case InputKeyLeft:
|
||||
instance->trigger -= TRIGGER_STEP;
|
||||
if(instance->trigger < RSSI_MIN + RSSI_SCALE * 2) instance->trigger = TRIGGER_MIN;
|
||||
break;
|
||||
default:
|
||||
case InputKeyRight:
|
||||
if(instance->trigger < RSSI_MIN + RSSI_SCALE * 2)
|
||||
instance->trigger = TRIGGER_MIN;
|
||||
else
|
||||
instance->trigger += TRIGGER_STEP;
|
||||
if(instance->trigger > RSSI_MAX) instance->trigger = RSSI_MAX;
|
||||
break;
|
||||
}
|
||||
if(instance->trigger > RSSI_MIN)
|
||||
FURI_LOG_I(TAG, "trigger = %.1f", (double)instance->trigger);
|
||||
else
|
||||
FURI_LOG_I(TAG, "trigger disabled");
|
||||
need_redraw = true;
|
||||
}
|
||||
|
||||
if(need_redraw) {
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
model->rssi_last = instance->rssi_last;
|
||||
model->frequency_last = instance->frequency_last;
|
||||
model->trigger = instance->trigger;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t round_int(uint32_t value, uint8_t n) {
|
||||
// Round value
|
||||
uint8_t on = n;
|
||||
while(n--) {
|
||||
uint8_t i = value % 10;
|
||||
value /= 10;
|
||||
if(i >= 5) value++;
|
||||
}
|
||||
while(on--) value *= 10;
|
||||
return value;
|
||||
}
|
||||
|
||||
void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) {
|
||||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
|
||||
if((rssi == 0.f) && (instance->locked)) {
|
||||
if(instance->callback) {
|
||||
instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context);
|
||||
}
|
||||
} else if((rssi != 0.f) && (!instance->locked)) {
|
||||
if(instance->callback) {
|
||||
instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context);
|
||||
notification_message(instance->notifications, &sequence_hw_blink);
|
||||
instance->triggered = false;
|
||||
}
|
||||
|
||||
if((rssi != 0.f) && (frequency != 0)) {
|
||||
// Threre is some signal
|
||||
FURI_LOG_I(TAG, "rssi = %.2f, frequency = %d Hz", (double)rssi, frequency);
|
||||
frequency = round_int(frequency, 3); // Round 299999990Hz to 300000000Hz
|
||||
if((instance->trigger <= RSSI_MIN + RSSI_SCALE * 2) || (rssi >= instance->trigger)) {
|
||||
if(!instance->triggered) {
|
||||
// Triggered!
|
||||
instance->triggered = true;
|
||||
instance->rssi_last = rssi;
|
||||
notification_message(instance->notifications, &sequence_hw_blink_stop);
|
||||
notification_message(instance->notifications, &sequence_success);
|
||||
FURI_LOG_D(TAG, "triggered");
|
||||
}
|
||||
// Update values
|
||||
if(rssi > instance->rssi_last) instance->rssi_last = rssi;
|
||||
instance->frequency_last = frequency;
|
||||
} else {
|
||||
instance->triggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +245,10 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency,
|
|||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
model->rssi = rssi;
|
||||
model->rssi_last = instance->rssi_last;
|
||||
model->frequency = frequency;
|
||||
model->frequency_last = instance->frequency_last;
|
||||
model->trigger = instance->trigger;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -110,6 +257,10 @@ 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);
|
||||
|
||||
|
@ -120,10 +271,18 @@ void subghz_frequency_analyzer_enter(void* context) {
|
|||
|
||||
subghz_frequency_analyzer_worker_start(instance->worker);
|
||||
|
||||
instance->rssi_last = 0;
|
||||
instance->frequency_last = 0;
|
||||
instance->trigger = TRIGGER_MIN;
|
||||
instance->triggered = false;
|
||||
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
model->rssi = 0;
|
||||
model->rssi_last = 0;
|
||||
model->frequency = 0;
|
||||
model->frequency_last = 0;
|
||||
model->trigger = instance->trigger;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -132,21 +291,21 @@ void subghz_frequency_analyzer_exit(void* context) {
|
|||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzer* instance = context;
|
||||
|
||||
//Stop worker
|
||||
// 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);
|
||||
}
|
||||
subghz_frequency_analyzer_worker_free(instance->worker);
|
||||
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
model->rssi = 0;
|
||||
return true;
|
||||
});
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
|
||||
SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer));
|
||||
furi_assert(instance);
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
@ -158,12 +317,6 @@ SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
|
|||
view_set_enter_callback(instance->view, subghz_frequency_analyzer_enter);
|
||||
view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit);
|
||||
|
||||
with_view_model(
|
||||
instance->view, (SubGhzFrequencyAnalyzerModel * model) {
|
||||
model->rssi = 0;
|
||||
return true;
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue