2015-07-08 08:39:24 -07: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-10 20:11:19 -08:00
# include "baseband_api.hpp"
2015-08-04 10:03:18 -07:00
# include "portapack_persistent_memory.hpp"
2016-12-09 18:21:47 +01:00
# include "hackrf_gpio.hpp"
2018-02-22 07:04:19 +00:00
# include "portapack.hpp"
2016-12-09 18:21:47 +01:00
using namespace hackrf : : one ;
2015-08-01 13:42:27 -07:00
using namespace portapack ;
2015-07-08 08:39:24 -07:00
2016-02-05 16:52:34 -08:00
# include "radio.hpp"
2016-02-05 16:25:43 -08:00
# include "audio.hpp"
2016-02-02 13:39:02 -08:00
# include "dsp_fir_taps.hpp"
# include "dsp_iir.hpp"
# include "dsp_iir_config.hpp"
namespace {
2022-11-19 18:17:54 +01: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
2016-02-02 13:39:02 -08:00
} } ;
2016-02-10 20:11:19 -08:00
static constexpr std : : array < baseband : : NBFMConfig , 3 > nbfm_configs { {
2016-02-02 13:39:02 -08:00
{ 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 } ,
} } ;
2023-05-07 16:08:45 +02:00
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 13:39:02 -08:00
} } ;
} /* namespace */
2015-07-08 08:39:24 -07:00
rf : : Frequency ReceiverModel : : tuning_frequency ( ) const {
2015-08-04 10:31:03 -07:00
return persistent_memory : : tuned_frequency ( ) ;
2015-07-08 08:39:24 -07:00
}
void ReceiverModel : : set_tuning_frequency ( rf : : Frequency f ) {
2015-08-04 10:31:03 -07:00
persistent_memory : : set_tuned_frequency ( f ) ;
2015-07-08 08:39:24 -07:00
update_tuning_frequency ( ) ;
}
rf : : Frequency ReceiverModel : : frequency_step ( ) const {
return frequency_step_ ;
}
void ReceiverModel : : set_frequency_step ( rf : : Frequency f ) {
frequency_step_ = f ;
}
2018-02-22 07:04:19 +00:00
void ReceiverModel : : set_antenna_bias ( ) {
2016-01-22 23:24:20 -08:00
update_antenna_bias ( ) ;
}
2015-07-08 08:39:24 -07:00
bool ReceiverModel : : rf_amp ( ) const {
return rf_amp_ ;
}
void ReceiverModel : : set_rf_amp ( bool enabled ) {
rf_amp_ = enabled ;
update_rf_amp ( ) ;
}
int32_t ReceiverModel : : lna ( ) const {
return lna_gain_db_ ;
}
void ReceiverModel : : set_lna ( int32_t v_db ) {
lna_gain_db_ = v_db ;
update_lna ( ) ;
}
uint32_t ReceiverModel : : baseband_bandwidth ( ) const {
return baseband_bandwidth_ ;
}
void ReceiverModel : : set_baseband_bandwidth ( uint32_t v ) {
baseband_bandwidth_ = v ;
update_baseband_bandwidth ( ) ;
}
int32_t ReceiverModel : : vga ( ) const {
return vga_gain_db_ ;
}
void ReceiverModel : : set_vga ( int32_t v_db ) {
vga_gain_db_ = v_db ;
update_vga ( ) ;
}
2016-08-03 16:13:54 -07:00
int32_t ReceiverModel : : tx_gain ( ) const {
return tx_gain_db_ ;
}
void ReceiverModel : : set_tx_gain ( int32_t v_db ) {
tx_gain_db_ = v_db ;
update_tx_gain ( ) ;
}
2015-07-08 08:39:24 -07:00
uint32_t ReceiverModel : : sampling_rate ( ) const {
2016-07-27 14:42:46 -07:00
return sampling_rate_ ;
}
void ReceiverModel : : set_sampling_rate ( uint32_t v ) {
sampling_rate_ = v ;
update_sampling_rate ( ) ;
2015-07-08 08:39:24 -07:00
}
2016-07-27 14:51:37 -07:00
ReceiverModel : : Mode ReceiverModel : : modulation ( ) const {
2016-07-27 14:42:46 -07:00
return mode_ ;
}
2016-07-27 14:51:37 -07:00
void ReceiverModel : : set_modulation ( const Mode v ) {
2016-07-27 14:42:46 -07:00
mode_ = v ;
update_modulation ( ) ;
2015-07-08 08:39:24 -07:00
}
volume_t ReceiverModel : : headphone_volume ( ) const {
return headphone_volume_ ;
}
void ReceiverModel : : set_headphone_volume ( volume_t v ) {
headphone_volume_ = v ;
update_headphone_volume ( ) ;
}
2017-06-11 09:50:29 +01:00
uint8_t ReceiverModel : : squelch_level ( ) const {
return squelch_level_ ;
}
void ReceiverModel : : set_squelch_level ( uint8_t v ) {
squelch_level_ = v ;
update_modulation ( ) ;
}
2015-07-08 08:39:24 -07:00
void ReceiverModel : : enable ( ) {
2016-01-23 11:31:50 -08:00
enabled_ = true ;
2015-07-08 08:39:24 -07:00
radio : : set_direction ( rf : : Direction : : Receive ) ;
update_tuning_frequency ( ) ;
2016-01-22 23:24:20 -08:00
update_antenna_bias ( ) ;
2015-07-08 08:39:24 -07:00
update_rf_amp ( ) ;
update_lna ( ) ;
update_vga ( ) ;
2016-08-03 16:13:54 -07:00
update_tx_gain ( ) ;
2015-07-08 08:39:24 -07:00
update_baseband_bandwidth ( ) ;
2016-07-27 14:41:36 -07:00
update_sampling_rate ( ) ;
2016-07-27 14:39:49 -07:00
update_modulation ( ) ;
2021-05-22 20:57:48 +01:00
// TODO: would challenge if this should belong to the
// receiver_model namespace:
2015-07-08 08:39:24 -07:00
update_headphone_volume ( ) ;
2021-05-22 20:57:48 +01:00
2016-12-09 18:21:47 +01:00
led_rx . on ( ) ;
2015-07-08 08:39:24 -07:00
}
2016-01-10 11:10:13 -08:00
void ReceiverModel : : disable ( ) {
2016-01-23 11:31:50 -08:00
enabled_ = false ;
2018-02-22 07:04:19 +00:00
radio : : set_antenna_bias ( false ) ;
2016-01-23 11:31:50 -08:00
// TODO: Responsibility for enabling/disabling the radio is muddy.
// Some happens in ReceiverModel, some inside radio namespace.
2015-07-08 08:39:24 -07:00
radio : : disable ( ) ;
2021-05-22 20:57:48 +01:00
// TODO: we are doing this repeatedly in different levels of the
// call stack. Keeping it for now, but there seem to be too many
// redundant calls:
2016-12-09 18:21:47 +01:00
led_rx . off ( ) ;
2015-07-08 08:39:24 -07:00
}
int32_t ReceiverModel : : tuning_offset ( ) {
2016-07-27 14:51:37 -07:00
if ( ( modulation ( ) = = Mode : : SpectrumAnalysis ) ) {
2015-08-27 13:57:31 -07:00
return 0 ;
} else {
return - ( sampling_rate ( ) / 4 ) ;
}
2015-07-08 08:39:24 -07:00
}
void ReceiverModel : : update_tuning_frequency ( ) {
2015-08-04 10:31:03 -07:00
radio : : set_tuning_frequency ( persistent_memory : : tuned_frequency ( ) + tuning_offset ( ) ) ;
2015-07-08 08:39:24 -07:00
}
2016-01-22 23:24:20 -08:00
void ReceiverModel : : update_antenna_bias ( ) {
2018-02-22 07:04:19 +00:00
if ( enabled_ )
radio : : set_antenna_bias ( portapack : : get_antenna_bias ( ) ) ;
2016-01-22 23:24:20 -08:00
}
2015-07-08 08:39:24 -07:00
void ReceiverModel : : update_rf_amp ( ) {
radio : : set_rf_amp ( rf_amp_ ) ;
}
void ReceiverModel : : update_lna ( ) {
radio : : set_lna_gain ( lna_gain_db_ ) ;
}
void ReceiverModel : : update_baseband_bandwidth ( ) {
radio : : set_baseband_filter_bandwidth ( baseband_bandwidth_ ) ;
}
void ReceiverModel : : update_vga ( ) {
radio : : set_vga_gain ( vga_gain_db_ ) ;
}
2016-08-03 16:13:54 -07:00
void ReceiverModel : : update_tx_gain ( ) {
radio : : set_tx_gain ( tx_gain_db_ ) ;
}
2016-02-02 13:39:02 -08:00
void ReceiverModel : : set_am_configuration ( const size_t n ) {
if ( n < am_configs . size ( ) ) {
am_config_index = n ;
2016-07-27 14:39:49 -07:00
update_modulation ( ) ;
2016-02-02 13:39:02 -08:00
}
}
void ReceiverModel : : set_nbfm_configuration ( const size_t n ) {
if ( n < nbfm_configs . size ( ) ) {
nbfm_config_index = n ;
2016-07-27 14:39:49 -07:00
update_modulation ( ) ;
2016-02-02 13:39:02 -08:00
}
}
void ReceiverModel : : set_wfm_configuration ( const size_t n ) {
if ( n < wfm_configs . size ( ) ) {
wfm_config_index = n ;
2016-07-27 14:39:49 -07:00
update_modulation ( ) ;
2016-02-02 13:39:02 -08:00
}
}
2016-07-27 14:41:36 -07:00
void ReceiverModel : : update_sampling_rate ( ) {
2016-01-10 11:01:54 -08: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.
// Disabling baseband while changing sampling rates seems like a good idea...
2016-08-21 11:31:37 -07:00
radio : : set_baseband_rate ( sampling_rate ( ) ) ;
2015-07-08 08:39:24 -07:00
update_tuning_frequency ( ) ;
}
void ReceiverModel : : update_headphone_volume ( ) {
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
// both?
2016-02-05 16:25:43 -08:00
audio : : headphone : : set_volume ( headphone_volume_ ) ;
2015-07-08 08:39:24 -07:00
}
2016-02-02 13:39:02 -08:00
2016-07-27 14:39:49 -07:00
void ReceiverModel : : update_modulation ( ) {
2016-07-27 14:51:37 -07:00
switch ( modulation ( ) ) {
2016-02-02 13:39:02 -08:00
default :
case Mode : : AMAudio :
update_am_configuration ( ) ;
break ;
case Mode : : NarrowbandFMAudio :
update_nbfm_configuration ( ) ;
break ;
case Mode : : WidebandFMAudio :
update_wfm_configuration ( ) ;
break ;
case Mode : : SpectrumAnalysis :
2018-12-18 16:25:21 +00:00
case Mode : : Capture :
2016-02-02 13:39:02 -08:00
break ;
}
}
2016-02-02 15:19:43 -08:00
size_t ReceiverModel : : am_configuration ( ) const {
return am_config_index ;
}
2016-02-02 13:39:02 -08:00
void ReceiverModel : : update_am_configuration ( ) {
am_configs [ am_config_index ] . apply ( ) ;
}
2016-02-02 15:19:43 -08:00
size_t ReceiverModel : : nbfm_configuration ( ) const {
return nbfm_config_index ;
}
2016-02-02 13:39:02 -08:00
void ReceiverModel : : update_nbfm_configuration ( ) {
2017-06-11 09:50:29 +01:00
nbfm_configs [ nbfm_config_index ] . apply ( squelch_level_ ) ;
2016-02-02 13:39:02 -08:00
}
2016-02-02 15:19:43 -08:00
size_t ReceiverModel : : wfm_configuration ( ) const {
return wfm_config_index ;
}
2016-02-02 13:39:02 -08:00
void ReceiverModel : : update_wfm_configuration ( ) {
wfm_configs [ wfm_config_index ] . apply ( ) ;
}
2023-01-21 11:36:06 +01:00
void ReceiverModel : : set_configuration_without_init ( const Mode new_mode , const rf : : Frequency new_frequency_step , const size_t new_am_config_index , const size_t new_nbfm_config_index , const size_t new_wfm_config_index , 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 ;
}