diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index b55250a7c..9e6e8f187 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -116,8 +116,8 @@ AMFMAptOptionsView::AMFMAptOptionsView( }); freqman_set_bandwidth_option(AMFM_MODULATION, options_config); // adding the common message from freqman.cpp to the options_config + receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal. options_config.set_by_value(receiver_model.amfm_configuration()); - receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal. } /* SPECOptionsView *******************************************************/ @@ -193,9 +193,10 @@ AnalogAudioView::AnalogAudioView( }; auto modulation = receiver_model.modulation(); + // This app doesn't handle "Capture" mode. - if (modulation > ReceiverModel::Mode::SpectrumAnalysis) // This two should be together in the last index position : SpectrumAnalysis = 4, and Capture = 5 - modulation = ReceiverModel::Mode::SpectrumAnalysis; // For sw simplicity , Wefax_mode, should NOT be added between. + if (modulation == ReceiverModel::Mode::Capture) + modulation = ReceiverModel::Mode::SpectrumAnalysis; options_modulation.set_by_value(toUType(modulation)); options_modulation.on_change = [this](size_t, OptionsField::value_t v) { @@ -285,10 +286,6 @@ void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) { } void AnalogAudioView::on_modulation_changed(ReceiverModel::Mode modulation) { - // This app doesn't know what to do with "Capture" mode. - if (modulation > ReceiverModel::Mode::SpectrumAnalysis) - modulation = ReceiverModel::Mode::SpectrumAnalysis; - baseband::spectrum_streaming_stop(); update_modulation(modulation); on_show_options_modulation(); diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index 29f01d514..daf606476 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -224,11 +224,13 @@ class AnalogAudioView : public View { OptionsField options_modulation{ {0 * 8, 0 * 16}, 4, - {{" AM ", toUType(ReceiverModel::Mode::AMAudio)}, - {"NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio)}, - {"WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio)}, - {"WFAX", toUType(ReceiverModel::Mode::AMAudioFMApt)}, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod - {"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)}}}; + { + {" AM ", toUType(ReceiverModel::Mode::AMAudio)}, + {"NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio)}, + {"WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio)}, + {"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)}, + {"AMFM", toUType(ReceiverModel::Mode::AMAudioFMApt)} // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod + }}; AudioVolumeField field_volume{ {28 * 8, 0 * 16}}; diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 7e230dc60..0018ed692 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -45,7 +45,7 @@ using option_db_t = std::pair; using options_db_t = std::vector; extern options_db_t freqman_modulations; -extern options_db_t freqman_bandwidths[4]; +extern options_db_t freqman_bandwidths[5]; extern options_db_t freqman_steps; extern options_db_t freqman_steps_short; diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index e5aa5ef7f..303fbeb42 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -277,6 +277,15 @@ size_t LevelView::change_mode(freqman_index_t new_mod) { field_bw.set_by_value(0); field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); }; break; + case AMFM_MODULATION: + audio_sampling_rate = audio::Rate::Hz_12000; + freqman_set_bandwidth_option(new_mod, field_bw); + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt); + receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal. + field_bw.set_by_value(0); + field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; }; + break; case SPEC_MODULATION: audio_sampling_rate = audio::Rate::Hz_24000; freqman_set_bandwidth_option(new_mod, field_bw); diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 977f9cbbb..88320d63d 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -1227,6 +1227,16 @@ size_t ReconView::change_mode(freqman_index_t new_mod) { text_ctcss.set(" "); recording_sampling_rate = 48000; break; + case AMFM_MODULATION: + freqman_set_bandwidth_option(new_mod, field_bw); + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt); + receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal. + field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; }; + field_bw.set_by_value(0); + text_ctcss.set(" "); + recording_sampling_rate = 12000; + break; case SPEC_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_capture); diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index edd0d6121..7c5ea1266 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -725,6 +725,14 @@ void ScannerView::change_mode(freqman_index_t new_mod) { field_bw.set_by_value(receiver_model.wfm_configuration()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); }; break; + case AMFM_MODULATION: + freqman_set_bandwidth_option(new_mod, field_bw); + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt); + receiver_model.set_amfm_configuration(5); + field_bw.set_by_value(0); + field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; }; + break; default: break; } diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 452a63b1a..0c8eaf68f 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -66,10 +66,10 @@ static void send_message(const Message* const message) { void AMConfig::apply() const { const AMConfigureMessage message{ - taps_6k0_decim_0, // common FIR filter taps pre-decim_0 to all 6 x AM mod types.(AM-9K, AM-6K, USB, LSB, CW, WFAX) + taps_6k0_decim_0, // common FIR filter taps pre-decim_0 to all 6 x AM mod types.(AM-9K, AM-6K, USB, LSB, CW, AMFM-WFAX) taps_6k0_decim_1, // common FIR filter taps pre-decim_1 to all 6 x AM mod. types. (") decim_2, // var decim_2 FIR taps filter , variable values, depending selected AM mod(AM 9k / 6k and all rest AM modes) - channel, // var channel FIR taps filter , variable values, depending selected AM mode, each one different (DSB-9K, DSB-6K, USB-3K, LSB-3K,CW,WFAX) + channel, // var channel FIR taps filter , variable values, depending selected AM mode, each one different (DSB-9K, DSB-6K, USB-3K, LSB-3K,CW,AMFM-WFAX) modulation, // var parameter . enum class Modulation : int32_t {DSB = 0, SSB = 1, SSB_FM = 2} audio_12k_iir_filter_config}; // var parameter , 300 Hz hpf all except Wefax (1.500Hz lpf) send_message(&message); diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp index 18c179f26..c4eba59e0 100644 --- a/firmware/application/freqman.hpp +++ b/firmware/application/freqman.hpp @@ -41,8 +41,8 @@ enum freqman_entry_modulation : uint8_t { AM_MODULATION = 0, NFM_MODULATION, WFM_MODULATION, - AMFM_MODULATION, // Added for Wefax. - SPEC_MODULATION + SPEC_MODULATION, + AMFM_MODULATION // Added for Wefax. }; // TODO: Can these be removed after Recon is migrated to FreqmanDB? diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index 59613e682..61150816f 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -49,6 +49,7 @@ options_t freqman_modulations = { {"NFM", 1}, {"WFM", 2}, {"SPEC", 3}, + {"AMFM", 4}, }; options_t freqman_bandwidths[5] = { @@ -72,10 +73,6 @@ options_t freqman_bandwidths[5] = { {"180k", 1}, {"200k", 0}, }, - { - // AMFM for Wefax- - {"USB+FM", 5}, // Fixed RX demodul AM config Index 5 : USB+FM for Audio Weather fax (Wfax) tones. - }, { // SPEC -- TODO: these should be indexes. {"12k5", 12500}, @@ -103,7 +100,12 @@ options_t freqman_bandwidths[5] = { {"4500k", 4500000}, {"5000k", 5500000}, {"5500k", 5500000}, // Max capture, needs /4 decimation, (22Mhz sampling ADC). - }}; + }, + { + // AMFM for Wefax- + {"USB+FM", 5}, // Fixed RX demodul AM config Index 5 : USB+FM for Audio Weather fax (WFAX) tones. + }, +}; // TODO: these should be indexes. options_t freqman_steps = { diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index 36ab728c1..25acd67f7 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -40,9 +40,9 @@ class ReceiverModel { AMAudio = 0, NarrowbandFMAudio = 1, WidebandFMAudio = 2, - AMAudioFMApt = 3, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod - SpectrumAnalysis = 4, - Capture = 5 + SpectrumAnalysis = 3, + AMAudioFMApt = 4, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod + Capture = 5, }; struct settings_t { diff --git a/firmware/baseband/audio_output.cpp b/firmware/baseband/audio_output.cpp index 313661dd6..b5e82a778 100644 --- a/firmware/baseband/audio_output.cpp +++ b/firmware/baseband/audio_output.cpp @@ -72,7 +72,7 @@ void AudioOutput::on_block(const buffer_f32_t& audio) { if (do_processing) { const auto audio_present_now = squelch.execute(audio); - hpf.execute_in_place(audio); // IIRBiquadFilter name is "hpf", but we will call with "hpf-coef" for all except WFAX with "lpf-coef". + hpf.execute_in_place(audio); // IIRBiquadFilter name is "hpf", but we will call with "hpf-coef" for all except AMFM (WFAX) with "lpf-coef" deemph.execute_in_place(audio); audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0); diff --git a/firmware/baseband/dsp_demodulate.cpp b/firmware/baseband/dsp_demodulate.cpp index 835e279fb..b5d45da5a 100644 --- a/firmware/baseband/dsp_demodulate.cpp +++ b/firmware/baseband/dsp_demodulate.cpp @@ -79,7 +79,7 @@ static inline float angle_precise(const complex32_t t) { return atan2f(t.imag(), t.real()); } -buffer_f32_t SSB_FM::execute( // Added to handle WFAX (HF weather map )- +buffer_f32_t SSB_FM::execute( // Added to handle AMFM (WFAX, HF weather map ) const buffer_c16_t& src, // input arg , pointer Complex c16 i,q buffer. const buffer_f32_t& dst) { // input arg , pointer f32 buffer audio demodulated complex16_t* src_p = src.p; // removed const ; init src_p pointer with the mem address pointed by src.p. diff --git a/firmware/baseband/dsp_demodulate.hpp b/firmware/baseband/dsp_demodulate.hpp index 1cb48699b..0b1ce0e2f 100644 --- a/firmware/baseband/dsp_demodulate.hpp +++ b/firmware/baseband/dsp_demodulate.hpp @@ -48,7 +48,7 @@ class SSB { static constexpr float k = 1.0f / 32768.0f; }; -class SSB_FM { // Added to handle WFAX- +class SSB_FM { // Added to handle AMFM for WFAX public: buffer_f32_t execute( const buffer_c16_t& src, @@ -56,7 +56,7 @@ class SSB_FM { // Added to handle WFAX- private: static constexpr float k = 1.0f / 32768.0f; - dsp::Real_to_Complex real_to_complex; // It is a member variable of SSB_FM. + dsp::Real_to_Complex real_to_complex{}; // It is a member variable of SSB_FM. }; class FM { diff --git a/firmware/baseband/proc_am_audio.cpp b/firmware/baseband/proc_am_audio.cpp index a1e0c8330..bb07264cd 100644 --- a/firmware/baseband/proc_am_audio.cpp +++ b/firmware/baseband/proc_am_audio.cpp @@ -65,7 +65,9 @@ buffer_f32_t NarrowbandAMAudio::demodulate(const buffer_c16_t& channel) { return demod_ssb_fm.execute(channel, audio_buffer); // Calling a derivative of demod_ssb (USB) , but with different FIR taps + FM audio tones demod. break; + // return demod am as a default default: + return demod_am.execute(channel, audio_buffer); break; } } diff --git a/firmware/common/dsp_sos_config.hpp b/firmware/common/dsp_sos_config.hpp index b55dc01d6..23766a19b 100644 --- a/firmware/common/dsp_sos_config.hpp +++ b/firmware/common/dsp_sos_config.hpp @@ -34,7 +34,7 @@ constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = { {1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f}}; // scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.99, btype = 'lowpass', output="sos") -// 6khz cutofff @fs:12Khz , used in WFAX demod. +// 6khz cutofff @fs:12Khz , used in AMFM demod for WFAX constexpr iir_biquad_df2_config_t full_band_lpf_config[5] = { {0.88095275f, 1.76184993f, 0.88095275f, 1.0f, 1.89055677f, 0.89616378f}, {1.0f, 1.99958798f, 1.0f, 1.0f, 1.9781807f, 0.98002549f}, @@ -43,7 +43,7 @@ constexpr iir_biquad_df2_config_t full_band_lpf_config[5] = { {1.0f, 1.99909558f, 1.0f, 1.0f, 1.9986187f, 0.99960319f}}; // scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5 , rs = 60.0, Wn = 0.25, btype = 'lowpass', output="sos") -// 1.5khz cutofff @fs:12Khz, used in WFAX demod. +// 1.5khz cutofff @fs:12Khz, used in AMFM demod for WFAX constexpr iir_biquad_df2_config_t quarter_band_lpf_config[5] = { {0.00349312f, 0.00319397f, 0.00349312f, 1.0f, -1.53025211f, 0.6203438f}, {1.0f, -0.83483341f, 1.0f, 1.0f, -1.47619047f, 0.77120659f}, diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 3afb0a7d9..8fb32c4f8 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -1329,6 +1329,9 @@ bool debug_dump() { case ReceiverModel::Mode::Capture: pmem_dump_file.write_line("modulation: Mode::Capture"); break; + case ReceiverModel::Mode::AMAudioFMApt: + pmem_dump_file.write_line("modulation: Mode::AMAudioFMApt"); + break; default: pmem_dump_file.write_line("modulation: !!unknown mode!!"); break;