2021-10-10 14:35:10 +00:00
# include "subghz_frequency_analyzer_worker.h"
2022-05-18 20:38:06 +00:00
# include <lib/drivers/cc1101.h>
2021-10-10 14:35:10 +00:00
# include <furi.h>
2022-12-26 12:13:30 +00:00
# include <float_tools.h>
2021-10-10 14:35:10 +00:00
2022-05-18 20:38:06 +00:00
# define TAG "SubghzFrequencyAnalyzerWorker"
2021-10-13 19:35:33 +00:00
static const uint8_t subghz_preset_ook_58khz [ ] [ 2 ] = {
2022-05-18 20:38:06 +00:00
{ CC1101_MDMCFG4 , 0 b11110111 } , // Rx BW filter is 58.035714kHz
2021-10-13 19:35:33 +00:00
/* End */
{ 0 , 0 } ,
} ;
static const uint8_t subghz_preset_ook_650khz [ ] [ 2 ] = {
2022-05-18 20:38:06 +00:00
{ CC1101_MDMCFG4 , 0 b00010111 } , // Rx BW filter is 650.000kHz
2021-10-13 19:35:33 +00:00
/* End */
{ 0 , 0 } ,
} ;
2021-10-10 14:35:10 +00:00
struct SubGhzFrequencyAnalyzerWorker {
FuriThread * thread ;
volatile bool worker_running ;
2022-05-18 20:38:06 +00:00
uint8_t sample_hold_counter ;
2021-10-10 14:35:10 +00:00
FrequencyRSSI frequency_rssi_buf ;
2022-04-14 14:05:40 +00:00
SubGhzSetting * setting ;
2021-10-10 14:35:10 +00:00
float filVal ;
SubGhzFrequencyAnalyzerWorkerPairCallback pair_callback ;
void * context ;
} ;
2022-05-18 20:38:06 +00:00
static void subghz_frequency_analyzer_worker_load_registers ( const uint8_t data [ ] [ 2 ] ) {
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
size_t i = 0 ;
while ( data [ i ] [ 0 ] ) {
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , data [ i ] [ 0 ] , data [ i ] [ 1 ] ) ;
i + + ;
}
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
}
2021-10-10 14:35:10 +00:00
// 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
2022-05-06 13:37:10 +00:00
if ( fabs ( newValFloat - instance - > filVal ) > 500000 )
2021-10-10 14:35:10 +00:00
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 ;
2022-06-21 13:30:30 +00:00
FrequencyRSSI frequency_rssi = {
. frequency_coarse = 0 , . rssi_coarse = 0 , . frequency_fine = 0 , . rssi_fine = 0 } ;
2022-05-18 20:38:06 +00:00
float rssi = 0 ;
uint32_t frequency = 0 ;
2022-11-23 13:31:39 +00:00
float rssi_temp = - 127.0f ;
2022-10-06 14:48:29 +00:00
uint32_t frequency_temp = 0 ;
2022-05-18 20:38:06 +00:00
CC1101Status status ;
2021-10-10 14:35:10 +00:00
//Start CC1101
furi_hal_subghz_reset ( ) ;
2022-05-18 20:38:06 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_flush_rx ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_flush_tx ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_IOCFG0 , CC1101IocfgHW ) ;
cc1101_write_reg ( & furi_hal_spi_bus_handle_subghz , CC1101_MDMCFG3 ,
2022-05-31 15:50:50 +00:00
0 b01111111 ) ; // symbol rate
2022-05-18 20:38:06 +00:00
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz ,
CC1101_AGCCTRL2 ,
0 b00000111 ) ; // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAGN_TARGET 42 dB
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz ,
CC1101_AGCCTRL1 ,
0 b00001000 ) ; // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 1000 - Absolute carrier sense threshold disabled
cc1101_write_reg (
& furi_hal_spi_bus_handle_subghz ,
CC1101_AGCCTRL0 ,
0 b00110000 ) ; // 00 - No hysteresis, medium asymmetric dead zone, medium gain ; 11 - 64 samples agc; 00 - Normal AGC, 00 - 4dB boundary
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2022-05-04 22:34:44 +00:00
furi_hal_subghz_set_path ( FuriHalSubGhzPathIsolate ) ;
2021-10-10 14:35:10 +00:00
while ( instance - > worker_running ) {
2022-07-20 10:56:33 +00:00
furi_delay_ms ( 10 ) ;
2022-05-18 20:38:06 +00:00
float rssi_min = 26.0f ;
float rssi_avg = 0 ;
size_t rssi_avg_samples = 0 ;
2022-06-21 13:30:30 +00:00
frequency_rssi . rssi_coarse = - 127.0f ;
frequency_rssi . rssi_fine = - 127.0f ;
2021-10-13 19:35:33 +00:00
furi_hal_subghz_idle ( ) ;
2022-05-18 20:38:06 +00:00
subghz_frequency_analyzer_worker_load_registers ( subghz_preset_ook_650khz ) ;
// First stage: coarse scan
2022-04-14 14:05:40 +00:00
for ( size_t i = 0 ; i < subghz_setting_get_frequency_count ( instance - > setting ) ; i + + ) {
if ( furi_hal_subghz_is_frequency_valid (
subghz_setting_get_frequency ( instance - > setting , i ) ) ) {
2022-05-18 20:38:06 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_switch_to_idle ( & furi_hal_spi_bus_handle_subghz ) ;
frequency = cc1101_set_frequency (
& furi_hal_spi_bus_handle_subghz ,
2022-04-14 14:05:40 +00:00
subghz_setting_get_frequency ( instance - > setting , i ) ) ;
2022-05-18 20:38:06 +00:00
cc1101_calibrate ( & furi_hal_spi_bus_handle_subghz ) ;
do {
status = cc1101_get_status ( & furi_hal_spi_bus_handle_subghz ) ;
} while ( status . STATE ! = CC1101StateIDLE ) ;
cc1101_switch_to_rx ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2022-07-20 10:56:33 +00:00
furi_delay_ms ( 2 ) ;
2022-05-18 20:38:06 +00:00
2021-10-10 14:35:10 +00:00
rssi = furi_hal_subghz_get_rssi ( ) ;
2022-05-18 20:38:06 +00:00
rssi_avg + = rssi ;
rssi_avg_samples + + ;
if ( rssi < rssi_min ) rssi_min = rssi ;
2022-06-21 13:30:30 +00:00
if ( frequency_rssi . rssi_coarse < rssi ) {
frequency_rssi . rssi_coarse = rssi ;
frequency_rssi . frequency_coarse = frequency ;
2021-10-10 14:35:10 +00:00
}
}
}
2022-05-18 20:38:06 +00:00
FURI_LOG_T (
TAG ,
2022-10-07 13:35:15 +00:00
" RSSI: avg %f, max %f at %lu, min %f " ,
2022-05-18 20:38:06 +00:00
( double ) ( rssi_avg / rssi_avg_samples ) ,
2022-06-21 13:30:30 +00:00
( double ) frequency_rssi . rssi_coarse ,
frequency_rssi . frequency_coarse ,
2022-05-18 20:38:06 +00:00
( double ) rssi_min ) ;
// Second stage: fine scan
2022-06-21 13:30:30 +00:00
if ( frequency_rssi . rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD ) {
2021-10-13 19:35:33 +00:00
furi_hal_subghz_idle ( ) ;
2022-05-18 20:38:06 +00:00
subghz_frequency_analyzer_worker_load_registers ( subghz_preset_ook_58khz ) ;
2022-06-21 13:30:30 +00:00
//for example -0.3 ... 433.92 ... +0.3 step 20KHz
for ( uint32_t i = frequency_rssi . frequency_coarse - 300000 ;
i < frequency_rssi . frequency_coarse + 300000 ;
2022-05-18 20:38:06 +00:00
i + = 20000 ) {
2021-10-10 14:35:10 +00:00
if ( furi_hal_subghz_is_frequency_valid ( i ) ) {
2022-05-18 20:38:06 +00:00
furi_hal_spi_acquire ( & furi_hal_spi_bus_handle_subghz ) ;
cc1101_switch_to_idle ( & furi_hal_spi_bus_handle_subghz ) ;
frequency = cc1101_set_frequency ( & furi_hal_spi_bus_handle_subghz , i ) ;
cc1101_calibrate ( & furi_hal_spi_bus_handle_subghz ) ;
do {
status = cc1101_get_status ( & furi_hal_spi_bus_handle_subghz ) ;
} while ( status . STATE ! = CC1101StateIDLE ) ;
cc1101_switch_to_rx ( & furi_hal_spi_bus_handle_subghz ) ;
furi_hal_spi_release ( & furi_hal_spi_bus_handle_subghz ) ;
2022-07-20 10:56:33 +00:00
furi_delay_ms ( 2 ) ;
2022-05-18 20:38:06 +00:00
2021-10-10 14:35:10 +00:00
rssi = furi_hal_subghz_get_rssi ( ) ;
2022-05-31 15:50:50 +00:00
2022-10-07 13:35:15 +00:00
FURI_LOG_T ( TAG , " #:%lu:%f " , frequency , ( double ) rssi ) ;
2022-05-31 15:50:50 +00:00
2022-06-21 13:30:30 +00:00
if ( frequency_rssi . rssi_fine < rssi ) {
frequency_rssi . rssi_fine = rssi ;
frequency_rssi . frequency_fine = frequency ;
2021-10-10 14:35:10 +00:00
}
}
}
}
2022-06-21 13:30:30 +00:00
// Deliver results fine
if ( frequency_rssi . rssi_fine > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD ) {
FURI_LOG_D (
2022-10-07 13:35:15 +00:00
TAG , " =:%lu:%f " , frequency_rssi . frequency_fine , ( double ) frequency_rssi . rssi_fine ) ;
2022-06-21 13:30:30 +00:00
instance - > sample_hold_counter = 20 ;
2022-11-23 13:31:39 +00:00
rssi_temp = ( rssi_temp + frequency_rssi . rssi_fine ) / 2 ;
2022-10-06 14:48:29 +00:00
frequency_temp = frequency_rssi . frequency_fine ;
2022-12-26 12:13:30 +00:00
if ( ! float_is_equal ( instance - > filVal , 0.f ) ) {
2022-06-21 13:30:30 +00:00
frequency_rssi . frequency_fine =
subghz_frequency_analyzer_worker_expRunningAverageAdaptive (
instance , frequency_rssi . frequency_fine ) ;
}
// Deliver callback
if ( instance - > pair_callback ) {
instance - > pair_callback (
2022-11-23 13:31:39 +00:00
instance - > context , frequency_rssi . frequency_fine , rssi_temp , true ) ;
2022-06-21 13:30:30 +00:00
}
} else if ( // Deliver results coarse
( frequency_rssi . rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD ) & &
( instance - > sample_hold_counter < 10 ) ) {
FURI_LOG_D (
TAG ,
2022-10-07 13:35:15 +00:00
" ~:%lu:%f " ,
2022-06-21 13:30:30 +00:00
frequency_rssi . frequency_coarse ,
( double ) frequency_rssi . rssi_coarse ) ;
2022-05-18 20:38:06 +00:00
instance - > sample_hold_counter = 20 ;
2022-11-23 13:31:39 +00:00
rssi_temp = ( rssi_temp + frequency_rssi . rssi_coarse ) / 2 ;
2022-10-06 14:48:29 +00:00
frequency_temp = frequency_rssi . frequency_coarse ;
2022-12-26 12:13:30 +00:00
if ( ! float_is_equal ( instance - > filVal , 0.f ) ) {
2022-06-21 13:30:30 +00:00
frequency_rssi . frequency_coarse =
2021-10-10 14:35:10 +00:00
subghz_frequency_analyzer_worker_expRunningAverageAdaptive (
2022-06-21 13:30:30 +00:00
instance , frequency_rssi . frequency_coarse ) ;
2021-10-10 14:35:10 +00:00
}
2022-05-18 20:38:06 +00:00
// Deliver callback
if ( instance - > pair_callback ) {
2021-10-10 14:35:10 +00:00
instance - > pair_callback (
2022-11-23 13:31:39 +00:00
instance - > context , frequency_rssi . frequency_coarse , rssi_temp , true ) ;
2022-05-18 20:38:06 +00:00
}
2021-10-10 14:35:10 +00:00
} else {
2022-05-18 20:38:06 +00:00
if ( instance - > sample_hold_counter > 0 ) {
instance - > sample_hold_counter - - ;
2022-11-23 13:31:39 +00:00
if ( instance - > sample_hold_counter = = 15 ) {
2022-10-06 14:48:29 +00:00
if ( instance - > pair_callback ) {
instance - > pair_callback (
instance - > context , frequency_temp , rssi_temp , false ) ;
}
}
2021-10-10 14:35:10 +00:00
} else {
instance - > filVal = 0 ;
2022-11-23 13:31:39 +00:00
rssi_temp = - 127.0f ;
instance - > pair_callback ( instance - > context , 0 , 0 , false ) ;
2021-10-10 14:35:10 +00:00
}
}
}
//Stop CC1101
furi_hal_subghz_idle ( ) ;
furi_hal_subghz_sleep ( ) ;
return 0 ;
}
2022-05-31 15:50:50 +00:00
SubGhzFrequencyAnalyzerWorker * subghz_frequency_analyzer_worker_alloc ( void * context ) {
furi_assert ( context ) ;
2022-02-18 19:53:46 +00:00
SubGhzFrequencyAnalyzerWorker * instance = malloc ( sizeof ( SubGhzFrequencyAnalyzerWorker ) ) ;
2021-10-10 14:35:10 +00:00
2022-11-23 12:49:17 +00:00
instance - > thread = furi_thread_alloc_ex (
" SubGhzFAWorker " , 2048 , subghz_frequency_analyzer_worker_thread , instance ) ;
2022-05-31 15:50:50 +00:00
SubGhz * subghz = context ;
instance - > setting = subghz - > setting ;
2021-10-10 14:35:10 +00:00
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 ;
}