2015-07-08 15:39:24 +00:00
/*
* Copyright ( C ) 2014 Jared Boone , ShareBrained Technology , Inc .
*
* This file is part of PortaPack .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , Inc . , 51 Franklin Street ,
* Boston , MA 02110 - 1301 , USA .
*/
# include "receiver_model.hpp"
2016-02-11 04:11:19 +00:00
# include "baseband_api.hpp"
2015-08-04 17:03:18 +00:00
# include "portapack_persistent_memory.hpp"
2016-12-09 17:21:47 +00:00
# include "hackrf_gpio.hpp"
2018-02-22 07:04:19 +00:00
# include "portapack.hpp"
2016-02-06 00:52:34 +00:00
# include "radio.hpp"
2016-02-06 00:25:43 +00:00
# include "audio.hpp"
2016-02-02 21:39:02 +00:00
# include "dsp_fir_taps.hpp"
# include "dsp_iir.hpp"
# include "dsp_iir_config.hpp"
2023-06-04 19:56:46 +00:00
# include "utility.hpp"
2016-02-02 21:39:02 +00:00
2023-06-11 18:47:13 +00:00
using namespace hackrf : : one ;
using namespace portapack ;
2016-02-02 21:39:02 +00:00
namespace {
2023-05-18 20:16:05 +00:00
static constexpr std : : array < baseband : : AMConfig , 5 > am_configs { {
// we config here all the non COMMON parameters to each AM modulation type in RX.
{ taps_9k0_decim_2 , taps_9k0_dsb_channel , AMConfigureMessage : : Modulation : : DSB } , // AM DSB-C BW 9khz (+-4k5) commercial EU bandwidth .
{ taps_6k0_decim_2 , taps_6k0_dsb_channel , AMConfigureMessage : : Modulation : : DSB } , // AM DSB-C BW 6khz (+-3k0) narrow AM , ham equipments.
{ taps_6k0_decim_2 , taps_2k8_usb_channel , AMConfigureMessage : : Modulation : : SSB } , // SSB USB BW 2K8 (+ 2K8)
{ taps_6k0_decim_2 , taps_2k8_lsb_channel , AMConfigureMessage : : Modulation : : SSB } , // SSB LSB BW 2K8 (- 2K8)
{ taps_6k0_decim_2 , taps_0k7_usb_channel , AMConfigureMessage : : Modulation : : SSB } , // SSB USB BW 0K7 (+ 0K7) used to get audio tone from CW Morse, assuming tx shifted +700hz aprox
} } ;
static constexpr std : : array < baseband : : NBFMConfig , 3 > nbfm_configs { {
{ taps_4k25_decim_0 , taps_4k25_decim_1 , taps_4k25_channel , 2500 } ,
{ taps_11k0_decim_0 , taps_11k0_decim_1 , taps_11k0_channel , 2500 } ,
{ taps_16k0_decim_0 , taps_16k0_decim_1 , taps_16k0_channel , 5000 } ,
} } ;
static constexpr std : : array < baseband : : WFMConfig , 3 > wfm_configs { {
{ taps_200k_wfm_decim_0 , taps_200k_wfm_decim_1 } ,
{ taps_180k_wfm_decim_0 , taps_180k_wfm_decim_1 } ,
{ taps_40k_wfm_decim_0 , taps_40k_wfm_decim_1 } ,
} } ;
2016-02-02 21:39:02 +00:00
} /* namespace */
2023-06-11 18:47:13 +00:00
rf : : Frequency ReceiverModel : : target_frequency ( ) const {
return persistent_memory : : target_frequency ( ) ;
2015-07-08 15:39:24 +00:00
}
2023-06-11 18:47:13 +00:00
void ReceiverModel : : set_target_frequency ( rf : : Frequency f ) {
persistent_memory : : set_target_frequency ( f ) ;
2023-05-18 20:16:05 +00:00
update_tuning_frequency ( ) ;
2015-07-08 15:39:24 +00:00
}
rf : : Frequency ReceiverModel : : frequency_step ( ) const {
2023-05-18 20:16:05 +00:00
return frequency_step_ ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_frequency_step ( rf : : Frequency f ) {
2023-05-18 20:16:05 +00:00
frequency_step_ = f ;
2015-07-08 15:39:24 +00:00
}
2018-02-22 07:04:19 +00:00
void ReceiverModel : : set_antenna_bias ( ) {
2023-05-18 20:16:05 +00:00
update_antenna_bias ( ) ;
2016-01-23 07:24:20 +00:00
}
2015-07-08 15:39:24 +00:00
bool ReceiverModel : : rf_amp ( ) const {
2023-05-18 20:16:05 +00:00
return rf_amp_ ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_rf_amp ( bool enabled ) {
2023-05-18 20:16:05 +00:00
rf_amp_ = enabled ;
update_rf_amp ( ) ;
2015-07-08 15:39:24 +00:00
}
int32_t ReceiverModel : : lna ( ) const {
2023-05-18 20:16:05 +00:00
return lna_gain_db_ ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_lna ( int32_t v_db ) {
2023-05-18 20:16:05 +00:00
lna_gain_db_ = v_db ;
update_lna ( ) ;
2015-07-08 15:39:24 +00:00
}
uint32_t ReceiverModel : : baseband_bandwidth ( ) const {
2023-05-18 20:16:05 +00:00
return baseband_bandwidth_ ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_baseband_bandwidth ( uint32_t v ) {
2023-05-18 20:16:05 +00:00
baseband_bandwidth_ = v ;
update_baseband_bandwidth ( ) ;
2015-07-08 15:39:24 +00:00
}
int32_t ReceiverModel : : vga ( ) const {
2023-05-18 20:16:05 +00:00
return vga_gain_db_ ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_vga ( int32_t v_db ) {
2023-05-18 20:16:05 +00:00
vga_gain_db_ = v_db ;
update_vga ( ) ;
2015-07-08 15:39:24 +00:00
}
uint32_t ReceiverModel : : sampling_rate ( ) const {
2023-05-18 20:16:05 +00:00
return sampling_rate_ ;
2016-07-27 21:42:46 +00:00
}
void ReceiverModel : : set_sampling_rate ( uint32_t v ) {
2023-05-18 20:16:05 +00:00
sampling_rate_ = v ;
update_sampling_rate ( ) ;
2015-07-08 15:39:24 +00:00
}
2016-07-27 21:51:37 +00:00
ReceiverModel : : Mode ReceiverModel : : modulation ( ) const {
2023-05-18 20:16:05 +00:00
return mode_ ;
2016-07-27 21:42:46 +00:00
}
2016-07-27 21:51:37 +00:00
void ReceiverModel : : set_modulation ( const Mode v ) {
2023-05-18 20:16:05 +00:00
mode_ = v ;
update_modulation ( ) ;
2015-07-08 15:39:24 +00:00
}
volume_t ReceiverModel : : headphone_volume ( ) const {
2023-06-05 18:09:50 +00:00
return persistent_memory : : headphone_volume ( ) ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : set_headphone_volume ( volume_t v ) {
2023-06-05 18:09:50 +00:00
persistent_memory : : set_headphone_volume ( v ) ;
2023-05-18 20:16:05 +00:00
update_headphone_volume ( ) ;
2015-07-08 15:39:24 +00:00
}
2023-06-11 18:47:13 +00:00
uint8_t ReceiverModel : : normalized_headphone_volume ( ) const {
auto db = ( headphone_volume ( ) - audio : : headphone : : volume_range ( ) . max ) . decibel ( ) ;
return clip < uint8_t > ( db + 99 , 0 , 99 ) ;
2023-06-04 19:56:46 +00:00
}
2023-06-11 18:47:13 +00:00
void ReceiverModel : : set_normalized_headphone_volume ( uint8_t v ) {
2023-06-05 18:09:50 +00:00
// TODO: Linear map instead to ensure 0 is minimal value or fix volume_range_t::normalize.
2023-06-11 18:47:13 +00:00
v = clip < uint8_t > ( v , 0 , 99 ) ;
2023-06-04 19:56:46 +00:00
auto new_volume = volume_t : : decibel ( v - 99 ) + audio : : headphone : : volume_range ( ) . max ;
set_headphone_volume ( new_volume ) ;
}
2017-06-11 08:50:29 +00:00
uint8_t ReceiverModel : : squelch_level ( ) const {
2023-05-18 20:16:05 +00:00
return squelch_level_ ;
2017-06-11 08:50:29 +00:00
}
void ReceiverModel : : set_squelch_level ( uint8_t v ) {
2023-05-18 20:16:05 +00:00
squelch_level_ = v ;
update_modulation ( ) ;
2017-06-11 08:50:29 +00:00
}
2015-07-08 15:39:24 +00:00
void ReceiverModel : : enable ( ) {
2023-05-18 20:16:05 +00:00
enabled_ = true ;
radio : : set_direction ( rf : : Direction : : Receive ) ;
update_tuning_frequency ( ) ;
update_antenna_bias ( ) ;
update_rf_amp ( ) ;
update_lna ( ) ;
update_vga ( ) ;
update_baseband_bandwidth ( ) ;
update_sampling_rate ( ) ;
update_modulation ( ) ;
2023-06-05 18:09:50 +00:00
// TODO: maybe not the perfect place for this, but it's reasonable.
2023-05-18 20:16:05 +00:00
update_headphone_volume ( ) ;
led_rx . on ( ) ;
2015-07-08 15:39:24 +00:00
}
2016-01-10 19:10:13 +00:00
void ReceiverModel : : disable ( ) {
2023-05-18 20:16:05 +00:00
enabled_ = false ;
2016-01-23 19:31:50 +00:00
2023-05-18 20:16:05 +00:00
// TODO: Responsibility for enabling/disabling the radio is muddy.
// Some happens in ReceiverModel, some inside radio namespace.
radio : : disable ( ) ;
led_rx . off ( ) ;
2015-07-08 15:39:24 +00:00
}
int32_t ReceiverModel : : tuning_offset ( ) {
2023-05-18 20:16:05 +00:00
if ( ( modulation ( ) = = Mode : : SpectrumAnalysis ) ) {
return 0 ;
} else {
return - ( sampling_rate ( ) / 4 ) ;
}
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : update_tuning_frequency ( ) {
2023-06-11 18:47:13 +00:00
// TODO: use positive offset if freq < offset.
radio : : set_tuning_frequency ( target_frequency ( ) + tuning_offset ( ) ) ;
2015-07-08 15:39:24 +00:00
}
2016-01-23 07:24:20 +00:00
void ReceiverModel : : update_antenna_bias ( ) {
2023-05-18 20:16:05 +00:00
if ( enabled_ )
radio : : set_antenna_bias ( portapack : : get_antenna_bias ( ) ) ;
2016-01-23 07:24:20 +00:00
}
2015-07-08 15:39:24 +00:00
void ReceiverModel : : update_rf_amp ( ) {
2023-05-18 20:16:05 +00:00
radio : : set_rf_amp ( rf_amp_ ) ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : update_lna ( ) {
2023-05-18 20:16:05 +00:00
radio : : set_lna_gain ( lna_gain_db_ ) ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : update_baseband_bandwidth ( ) {
2023-05-18 20:16:05 +00:00
radio : : set_baseband_filter_bandwidth ( baseband_bandwidth_ ) ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : update_vga ( ) {
2023-05-18 20:16:05 +00:00
radio : : set_vga_gain ( vga_gain_db_ ) ;
2015-07-08 15:39:24 +00:00
}
2016-02-02 21:39:02 +00:00
void ReceiverModel : : set_am_configuration ( const size_t n ) {
2023-05-18 20:16:05 +00:00
if ( n < am_configs . size ( ) ) {
am_config_index = n ;
update_modulation ( ) ;
}
2016-02-02 21:39:02 +00:00
}
void ReceiverModel : : set_nbfm_configuration ( const size_t n ) {
2023-05-18 20:16:05 +00:00
if ( n < nbfm_configs . size ( ) ) {
nbfm_config_index = n ;
update_modulation ( ) ;
}
2016-02-02 21:39:02 +00:00
}
void ReceiverModel : : set_wfm_configuration ( const size_t n ) {
2023-05-18 20:16:05 +00:00
if ( n < wfm_configs . size ( ) ) {
wfm_config_index = n ;
update_modulation ( ) ;
}
2016-02-02 21:39:02 +00:00
}
2023-06-17 14:54:52 +00:00
void ReceiverModel : : set_configuration_without_update (
uint32_t baseband_bandwidth ,
uint32_t sampling_rate ) {
baseband_bandwidth_ = baseband_bandwidth ;
sampling_rate_ = sampling_rate ;
}
void ReceiverModel : : set_configuration_without_update (
Mode new_mode ,
rf : : Frequency new_frequency_step ,
size_t new_am_config_index ,
size_t new_nbfm_config_index ,
size_t new_wfm_config_index ,
2023-06-11 18:47:13 +00:00
uint8_t new_squelch_level ) {
mode_ = new_mode ;
frequency_step_ = new_frequency_step ;
am_config_index = new_am_config_index ;
nbfm_config_index = new_nbfm_config_index ;
wfm_config_index = new_wfm_config_index ;
squelch_level_ = new_squelch_level ;
}
void ReceiverModel : : configure_from_app_settings (
const app_settings : : AppSettings & settings ) {
baseband_bandwidth_ = settings . baseband_bandwidth ;
sampling_rate_ = settings . sampling_rate ;
lna_gain_db_ = settings . lna ;
vga_gain_db_ = settings . vga ;
rf_amp_ = settings . rx_amp ;
squelch_level_ = settings . squelch ;
}
2016-07-27 21:41:36 +00:00
void ReceiverModel : : update_sampling_rate ( ) {
2023-05-18 20:16:05 +00:00
// TODO: Move more low-level radio control stuff to M4. It'll enable tighter
// synchronization for things like wideband (sweeping) spectrum analysis, and
// protocols that need quick RX/TX turn-around.
2016-01-10 19:01:54 +00:00
2023-05-18 20:16:05 +00:00
// Disabling baseband while changing sampling rates seems like a good idea...
radio : : set_baseband_rate ( sampling_rate ( ) ) ;
update_tuning_frequency ( ) ;
2015-07-08 15:39:24 +00:00
}
void ReceiverModel : : update_headphone_volume ( ) {
2023-06-05 18:09:50 +00:00
audio : : headphone : : set_volume ( headphone_volume ( ) ) ;
2015-07-08 15:39:24 +00:00
}
2016-02-02 21:39:02 +00:00
2016-07-27 21:39:49 +00:00
void ReceiverModel : : update_modulation ( ) {
2023-05-18 20:16:05 +00:00
switch ( modulation ( ) ) {
default :
case Mode : : AMAudio :
update_am_configuration ( ) ;
break ;
2016-02-02 21:39:02 +00:00
2023-05-18 20:16:05 +00:00
case Mode : : NarrowbandFMAudio :
update_nbfm_configuration ( ) ;
break ;
2016-02-02 21:39:02 +00:00
2023-05-18 20:16:05 +00:00
case Mode : : WidebandFMAudio :
update_wfm_configuration ( ) ;
break ;
2016-02-02 21:39:02 +00:00
2023-05-18 20:16:05 +00:00
case Mode : : SpectrumAnalysis :
case Mode : : Capture :
break ;
}
2016-02-02 21:39:02 +00:00
}
2016-02-02 23:19:43 +00:00
size_t ReceiverModel : : am_configuration ( ) const {
2023-05-18 20:16:05 +00:00
return am_config_index ;
2016-02-02 23:19:43 +00:00
}
2016-02-02 21:39:02 +00:00
void ReceiverModel : : update_am_configuration ( ) {
2023-05-18 20:16:05 +00:00
am_configs [ am_config_index ] . apply ( ) ;
2016-02-02 21:39:02 +00:00
}
2016-02-02 23:19:43 +00:00
size_t ReceiverModel : : nbfm_configuration ( ) const {
2023-05-18 20:16:05 +00:00
return nbfm_config_index ;
2016-02-02 23:19:43 +00:00
}
2016-02-02 21:39:02 +00:00
void ReceiverModel : : update_nbfm_configuration ( ) {
2023-05-18 20:16:05 +00:00
nbfm_configs [ nbfm_config_index ] . apply ( squelch_level_ ) ;
2016-02-02 21:39:02 +00:00
}
2016-02-02 23:19:43 +00:00
size_t ReceiverModel : : wfm_configuration ( ) const {
2023-05-18 20:16:05 +00:00
return wfm_config_index ;
2016-02-02 23:19:43 +00:00
}
2016-02-02 21:39:02 +00:00
void ReceiverModel : : update_wfm_configuration ( ) {
2023-05-18 20:16:05 +00:00
wfm_configs [ wfm_config_index ] . apply ( ) ;
2016-02-02 21:39:02 +00:00
}