diff options
author | Skorpionm <85568270+Skorpionm@users.noreply.github.com> | 2021-10-10 17:35:10 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-10 17:35:10 +0300 |
commit | 4418e73b261969858f493402a30798f589e9df4f (patch) | |
tree | 45bd89b132bc178ed7cb3e304807adbf60f6915e /applications/subghz | |
parent | 5dbfe3d90afaad41d86ab4e6e402031b290d0c2e (diff) |
[FL-1912, FL-1939] Sub-GHz frequency analyzer and add new protocol (#746)
* ToolBox: add manchester-decoder and manchester-encoder
* SubGhz: add new FM config cc1101
* Subghz: add protocol Kia
* SubGhz: fix receiving the last packet Nero Radio
* SubGhz: app protocol CAME Twin (TW2EE/TW4EE)
* SubGhz: add protocol CAME Atomo (AT03EV/ AT04EV)
* F7: sync with F6
* SubGhz: add frequency analyzer
* SubGhz: remove space from file name
* SubGhz: frequency analyzer add filter and fix view
* [FL-1939] GubGhz: Frequency analyzer redesign
* SubGhz: fix incorrect subghz api call sequence in frequency analyzer worker
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Diffstat (limited to 'applications/subghz')
-rw-r--r-- | applications/subghz/helpers/subghz_frequency_analyzer_worker.c | 171 | ||||
-rw-r--r-- | applications/subghz/helpers/subghz_frequency_analyzer_worker.h | 54 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_config.h | 1 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_delete.c | 4 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_frequency_analyzer.c | 30 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_receiver.c | 4 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_receiver_config.c | 8 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_receiver_info.c | 4 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_set_type.c | 16 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_start.c | 12 | ||||
-rw-r--r-- | applications/subghz/scenes/subghz_scene_transmitter.c | 4 | ||||
-rw-r--r-- | applications/subghz/subghz.c | 11 | ||||
-rw-r--r-- | applications/subghz/subghz_i.h | 3 | ||||
-rw-r--r-- | applications/subghz/views/subghz_frequency_analyzer.c | 170 | ||||
-rw-r--r-- | applications/subghz/views/subghz_frequency_analyzer.h | 22 |
15 files changed, 507 insertions, 7 deletions
diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c new file mode 100644 index 00000000..a720006d --- /dev/null +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -0,0 +1,171 @@ +#include "subghz_frequency_analyzer_worker.h" + +#include <furi.h> + +#include "../subghz_i.h" + +struct SubGhzFrequencyAnalyzerWorker { + FuriThread* thread; + + volatile bool worker_running; + uint8_t count_repet; + FrequencyRSSI frequency_rssi_buf; + + float filVal; + + SubGhzFrequencyAnalyzerWorkerPairCallback pair_callback; + void* context; +}; + +// running average with adaptive coefficient +static uint32_t subghz_frequency_analyzer_worker_expRunningAverageAdaptive( + SubGhzFrequencyAnalyzerWorker* instance, + uint32_t newVal) { + float k; + float newValFloat = newVal; + // the sharpness of the filter depends on the absolute value of the difference + if(abs(newValFloat - instance->filVal) > 500000) + k = 0.9; + else + k = 0.03; + + instance->filVal += (newValFloat - instance->filVal) * k; + return (uint32_t)instance->filVal; +} + +/** Worker thread + * + * @param context + * @return exit code + */ +static int32_t subghz_frequency_analyzer_worker_thread(void* context) { + SubGhzFrequencyAnalyzerWorker* instance = context; + + FrequencyRSSI frequency_rssi; + float rssi; + uint32_t frequency; + uint32_t frequency_start; + + //Start CC1101 + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_set_frequency(433920000); + furi_hal_subghz_flush_rx(); + furi_hal_subghz_rx(); + + while(instance->worker_running) { + osDelay(10); + frequency_rssi.rssi = -127.0f; + for(size_t i = 0; i < subghz_frequencies_count; i++) { + if(furi_hal_subghz_is_frequency_valid(subghz_frequencies[i])) { + furi_hal_subghz_idle(); + frequency = furi_hal_subghz_set_frequency(subghz_frequencies[i]); + furi_hal_subghz_rx(); + osDelay(3); + rssi = furi_hal_subghz_get_rssi(); + if(frequency_rssi.rssi < rssi) { + frequency_rssi.rssi = rssi; + frequency_rssi.frequency = frequency; + } + } + } + + if(frequency_rssi.rssi > -90.0) { + // -0.5 ... 433.92 ... +0.5 + frequency_start = frequency_rssi.frequency - 250000; + //step 10KHz + for(uint32_t i = frequency_start; i < frequency_start + 500000; i += 10000) { + if(furi_hal_subghz_is_frequency_valid(i)) { + furi_hal_subghz_idle(); + frequency = furi_hal_subghz_set_frequency(i); + furi_hal_subghz_rx(); + osDelay(3); + rssi = furi_hal_subghz_get_rssi(); + if(frequency_rssi.rssi < rssi) { + frequency_rssi.rssi = rssi; + frequency_rssi.frequency = frequency; + } + } + } + } + + if(frequency_rssi.rssi > -90.0) { + instance->count_repet = 20; + if(instance->filVal) { + frequency_rssi.frequency = + subghz_frequency_analyzer_worker_expRunningAverageAdaptive( + instance, frequency_rssi.frequency); + } + if(instance->pair_callback) + instance->pair_callback( + instance->context, frequency_rssi.frequency, frequency_rssi.rssi); + + } else { + if(instance->count_repet > 0) { + instance->count_repet--; + } else { + instance->filVal = 0; + if(instance->pair_callback) instance->pair_callback(instance->context, 0, 0); + } + } + } + + //Stop CC1101 + furi_hal_subghz_idle(); + furi_hal_subghz_sleep(); + + return 0; +} + +SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() { + SubGhzFrequencyAnalyzerWorker* instance = furi_alloc(sizeof(SubGhzFrequencyAnalyzerWorker)); + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "subghz_frequency_analyzer_worker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); + + return instance; +} + +void subghz_frequency_analyzer_worker_free(SubGhzFrequencyAnalyzerWorker* instance) { + furi_assert(instance); + + furi_thread_free(instance->thread); + + free(instance); +} + +void subghz_frequency_analyzer_worker_set_pair_callback( + SubGhzFrequencyAnalyzerWorker* instance, + SubGhzFrequencyAnalyzerWorkerPairCallback callback, + void* context) { + furi_assert(instance); + furi_assert(context); + instance->pair_callback = callback; + instance->context = context; +} + +void subghz_frequency_analyzer_worker_start(SubGhzFrequencyAnalyzerWorker* instance) { + furi_assert(instance); + furi_assert(!instance->worker_running); + + instance->worker_running = true; + + furi_thread_start(instance->thread); +} + +void subghz_frequency_analyzer_worker_stop(SubGhzFrequencyAnalyzerWorker* instance) { + furi_assert(instance); + furi_assert(instance->worker_running); + + instance->worker_running = false; + + furi_thread_join(instance->thread); +} + +bool subghz_frequency_analyzer_worker_is_running(SubGhzFrequencyAnalyzerWorker* instance) { + furi_assert(instance); + return instance->worker_running; +} diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h new file mode 100644 index 00000000..34998ff1 --- /dev/null +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -0,0 +1,54 @@ +#pragma once + +#include <furi-hal.h> + +typedef struct SubGhzFrequencyAnalyzerWorker SubGhzFrequencyAnalyzerWorker; + +typedef void ( + *SubGhzFrequencyAnalyzerWorkerPairCallback)(void* context, uint32_t frequency, float rssi); + +typedef struct { + uint32_t frequency; + float rssi; +} FrequencyRSSI; + +/** Allocate SubGhzFrequencyAnalyzerWorker + * + * @return SubGhzFrequencyAnalyzerWorker* + */ +SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(); + +/** Free SubGhzFrequencyAnalyzerWorker + * + * @param instance SubGhzFrequencyAnalyzerWorker instance + */ +void subghz_frequency_analyzer_worker_free(SubGhzFrequencyAnalyzerWorker* instance); + +/** Pair callback SubGhzFrequencyAnalyzerWorker + * + * @param instance SubGhzFrequencyAnalyzerWorker instance + * @param callback SubGhzFrequencyAnalyzerWorkerOverrunCallback callback + * @param context + */ +void subghz_frequency_analyzer_worker_set_pair_callback( + SubGhzFrequencyAnalyzerWorker* instance, + SubGhzFrequencyAnalyzerWorkerPairCallback callback, + void* context); + +/** Start SubGhzFrequencyAnalyzerWorker + * + * @param instance SubGhzFrequencyAnalyzerWorker instance + */ +void subghz_frequency_analyzer_worker_start(SubGhzFrequencyAnalyzerWorker* instance); + +/** Stop SubGhzFrequencyAnalyzerWorker + * + * @param instance SubGhzFrequencyAnalyzerWorker instance + */ +void subghz_frequency_analyzer_worker_stop(SubGhzFrequencyAnalyzerWorker* instance); + +/** Check if worker is running + * @param instance SubGhzFrequencyAnalyzerWorker instance + * @return bool - true if running + */ +bool subghz_frequency_analyzer_worker_is_running(SubGhzFrequencyAnalyzerWorker* instance); diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index 7958764d..eca3cc35 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -16,3 +16,4 @@ ADD_SCENE(subghz, test_static, TestStatic) ADD_SCENE(subghz, test_carrier, TestCarrier) ADD_SCENE(subghz, test_packet, TestPacket) ADD_SCENE(subghz, set_type, SetType) +ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer)
\ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/subghz/scenes/subghz_scene_delete.c index e97fd989..94782e88 100644 --- a/applications/subghz/scenes/subghz_scene_delete.c +++ b/applications/subghz/scenes/subghz_scene_delete.c @@ -28,7 +28,9 @@ void subghz_scene_delete_on_enter(void* context) { if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { snprintf(buffer_str, sizeof(buffer_str), "AM"); - } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + } else if( + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { snprintf(buffer_str, sizeof(buffer_str), "FM"); } else { furi_crash(NULL); diff --git a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c new file mode 100644 index 00000000..b67494f0 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -0,0 +1,30 @@ +#include "../subghz_i.h" +#include "../views/subghz_frequency_analyzer.h" + +void subghz_scene_frequency_analyzer_callback(SubghzFrequencyAnalyzerEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +void subghz_scene_frequency_analyzer_on_enter(void* context) { + SubGhz* subghz = context; + subghz_frequency_analyzer_set_callback( + subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); +} + +bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzFrequencyAnalyzerEventOnlyRx) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + return true; + } + } + return false; +} + +void subghz_scene_frequency_analyzer_on_exit(void* context) { + // SubGhz* subghz = context; +} diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index f2d66e6b..fe29c0cf 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -17,7 +17,9 @@ static void subghz_scene_receiver_update_statusbar(void* context) { if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { snprintf(preset_str, sizeof(preset_str), "AM"); - } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + } else if( + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { snprintf(preset_str, sizeof(preset_str), "FM"); } else { furi_crash(NULL); diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c index 9586c8f3..3991a999 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -1,15 +1,17 @@ #include "../subghz_i.h" -#define PRESET_COUNT 3 +#define PRESET_COUNT 4 const char* const preset_text[PRESET_COUNT] = { "AM270", "AM650", - "FM", + "FM238", + "FM476", }; const uint32_t preset_value[PRESET_COUNT] = { FuriHalSubGhzPresetOok270Async, /** OOK, bandwidth 270kHz, asynchronous */ FuriHalSubGhzPresetOok650Async, /** OOK, bandwidth 650kHz, asynchronous */ - FuriHalSubGhzPreset2FSKAsync, /** FM, asynchronous */ + FuriHalSubGhzPreset2FSKDev238Async, /** FM, deviation 2.380371 kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev476Async, /** FM, deviation 4.760742 kHz, asynchronous */ }; #define HOPPING_COUNT 2 diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c index f3a75e54..6b33a686 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/subghz/scenes/subghz_scene_receiver_info.c @@ -57,7 +57,9 @@ void subghz_scene_receiver_info_on_enter(void* context) { if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { snprintf(buffer_str, sizeof(buffer_str), "AM"); - } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + } else if( + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { snprintf(buffer_str, sizeof(buffer_str), "FM"); } else { furi_crash(NULL); diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index 4ec34e23..331b9dc2 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -7,6 +7,7 @@ enum SubmenuIndex { SubmenuIndexNiceFlo24bit, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, + SubmenuIndexCAMETwee, SubmenuIndexNeroSketch, SubmenuIndexNeroRadio, SubmenuIndexGateTX, @@ -62,6 +63,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexCAME24bit, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "CAME TWEE", + SubmenuIndexCAMETwee, + subghz_scene_set_type_submenu_callback, + subghz); // submenu_add_item( // subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz); // submenu_add_item( @@ -132,6 +139,15 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; + case SubmenuIndexCAMETwee: + if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME TWEE")) { + subghz->txrx->protocol_result->code_last_count_bit = 54; + key = (key & 0x0FFFFFF0); + subghz->txrx->protocol_result->code_last_found = 0x003FFF7200000000 | + (key ^ 0xE0E0E0EE); + generated_protocol = true; + } + break; // case SubmenuIndexNeroSketch: // /* code */ // break; diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c index b3713873..c131a0a8 100644 --- a/applications/subghz/scenes/subghz_scene_start.c +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -5,6 +5,7 @@ enum SubmenuIndex { SubmenuIndexSaved, SubmenuIndexTest, SubmenuIndexAddManualy, + SubmenuIndexFrequencyAnalyzer, }; void subghz_scene_start_submenu_callback(void* context, uint32_t index) { @@ -28,6 +29,12 @@ void subghz_scene_start_on_enter(void* context) { subghz_scene_start_submenu_callback, subghz); submenu_add_item( + subghz->submenu, + "Frequency Analyzer", + SubmenuIndexFrequencyAnalyzer, + subghz_scene_start_submenu_callback, + subghz); + submenu_add_item( subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); submenu_set_selected_item( @@ -55,6 +62,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManualy); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); return true; + } else if(event.event == SubmenuIndexFrequencyAnalyzer) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); + return true; } else if(event.event == SubmenuIndexTest) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index 85c61240..4aa5f87f 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -36,7 +36,9 @@ static void subghz_scene_transmitter_update_data_show(void* context) { if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { snprintf(preset_str, sizeof(preset_str), "AM"); - } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + } else if( + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || + subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { snprintf(preset_str, sizeof(preset_str), "FM"); } else { furi_crash(NULL); diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 38145697..7c71e25f 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -133,6 +133,13 @@ SubGhz* subghz_alloc() { SubGhzViewVariableItemList, variable_item_list_get_view(subghz->variable_item_list)); + // Frequency Analyzer + subghz->subghz_frequency_analyzer = subghz_frequency_analyzer_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, + SubGhzViewFrequencyAnalyzer, + subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer)); + // Carrier Test Module subghz->subghz_test_carrier = subghz_test_carrier_alloc(); view_dispatcher_add_view( @@ -215,6 +222,10 @@ void subghz_free(SubGhz* subghz) { view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList); variable_item_list_free(subghz->variable_item_list); + // Frequency Analyzer + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); + subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer); + // Submenu view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); submenu_free(subghz->submenu); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index dc1e5a3f..88be9203 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -3,6 +3,7 @@ #include "subghz.h" #include "views/subghz_receiver.h" #include "views/subghz_transmitter.h" +#include "views/subghz_frequency_analyzer.h" #include "views/subghz_test_static.h" #include "views/subghz_test_carrier.h" @@ -98,6 +99,7 @@ struct SubGhz { SubghzTransmitter* subghz_transmitter; VariableItemList* variable_item_list; + SubghzFrequencyAnalyzer* subghz_frequency_analyzer; SubghzTestStatic* subghz_test_static; SubghzTestCarrier* subghz_test_carrier; SubghzTestPacket* subghz_test_packet; @@ -113,6 +115,7 @@ typedef enum { SubGhzViewWidget, SubGhzViewTransmitter, SubGhzViewVariableItemList, + SubGhzViewFrequencyAnalyzer, SubGhzViewStatic, SubGhzViewTestCarrier, SubGhzViewTestPacket, diff --git a/applications/subghz/views/subghz_frequency_analyzer.c b/applications/subghz/views/subghz_frequency_analyzer.c new file mode 100644 index 00000000..c4e6d6bf --- /dev/null +++ b/applications/subghz/views/subghz_frequency_analyzer.c @@ -0,0 +1,170 @@ +#include "subghz_frequency_analyzer.h" +#include "../subghz_i.h" + +#include <math.h> +#include <furi.h> +#include <furi-hal.h> +#include <input/input.h> +#include <notification/notification-messages.h> +#include <lib/subghz/protocols/subghz_protocol_princeton.h> +#include "../helpers/subghz_frequency_analyzer_worker.h" + +#include <assets_icons.h> + +typedef enum { + SubghzFrequencyAnalyzerStatusIDLE, +} SubghzFrequencyAnalyzerStatus; + +struct SubghzFrequencyAnalyzer { + View* view; + SubGhzFrequencyAnalyzerWorker* worker; + SubghzFrequencyAnalyzerCallback callback; + void* context; +}; + +typedef struct { + uint32_t frequency; + float rssi; +} SubghzFrequencyAnalyzerModel; + +void subghz_frequency_analyzer_set_callback( + SubghzFrequencyAnalyzer* subghz_frequency_analyzer, + SubghzFrequencyAnalyzerCallback callback, + void* context) { + furi_assert(subghz_frequency_analyzer); + furi_assert(callback); + subghz_frequency_analyzer->callback = 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; + if(rssi) { + rssi = (rssi + 90) / 3; + 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); + } + } + } +} + +void subghz_frequency_analyzer_draw(Canvas* canvas, SubghzFrequencyAnalyzerModel* model) { + char buffer[64]; + + 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); + + //Frequency + canvas_set_font(canvas, FontBigNumbers); + snprintf( + buffer, + sizeof(buffer), + "%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); +} + +bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { + furi_assert(context); + //SubghzFrequencyAnalyzer* instance = context; + + if(event->key == InputKeyBack) { + return false; + } + + return true; +} + +void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) { + SubghzFrequencyAnalyzer* instance = context; + with_view_model( + instance->view, (SubghzFrequencyAnalyzerModel * model) { + model->rssi = rssi; + model->frequency = frequency; + return true; + }); +} + +void subghz_frequency_analyzer_enter(void* context) { + furi_assert(context); + SubghzFrequencyAnalyzer* instance = context; + + //Start worker + instance->worker = subghz_frequency_analyzer_worker_alloc(); + + subghz_frequency_analyzer_worker_set_pair_callback( + instance->worker, + (SubGhzFrequencyAnalyzerWorkerPairCallback)subghz_frequency_analyzer_pair_callback, + instance); + + subghz_frequency_analyzer_worker_start(instance->worker); + + with_view_model( + instance->view, (SubghzFrequencyAnalyzerModel * model) { + model->rssi = 0; + model->frequency = 0; + return true; + }); +} + +void subghz_frequency_analyzer_exit(void* context) { + furi_assert(context); + SubghzFrequencyAnalyzer* instance = context; + + //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; + }); +} + +SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { + SubghzFrequencyAnalyzer* instance = furi_alloc(sizeof(SubghzFrequencyAnalyzer)); + + // View allocation and configuration + instance->view = view_alloc(); + view_allocate_model( + instance->view, ViewModelTypeLocking, sizeof(SubghzFrequencyAnalyzerModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw); + view_set_input_callback(instance->view, subghz_frequency_analyzer_input); + 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; +} + +void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* instance) { + furi_assert(instance); + return instance->view; +}
\ No newline at end of file diff --git a/applications/subghz/views/subghz_frequency_analyzer.h b/applications/subghz/views/subghz_frequency_analyzer.h new file mode 100644 index 00000000..ebfcb173 --- /dev/null +++ b/applications/subghz/views/subghz_frequency_analyzer.h @@ -0,0 +1,22 @@ +#pragma once + +#include <gui/view.h> + +typedef enum { + SubghzFrequencyAnalyzerEventOnlyRx, +} SubghzFrequencyAnalyzerEvent; + +typedef struct SubghzFrequencyAnalyzer SubghzFrequencyAnalyzer; + +typedef void (*SubghzFrequencyAnalyzerCallback)(SubghzFrequencyAnalyzerEvent event, void* context); + +void subghz_frequency_analyzer_set_callback( + SubghzFrequencyAnalyzer* subghz_frequency_analyzer, + SubghzFrequencyAnalyzerCallback callback, + void* context); + +SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc(); + +void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* subghz_static); + +View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* subghz_static); |