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