diff --git a/firmware/application/apps/ui_about_simple.cpp b/firmware/application/apps/ui_about_simple.cpp index 60b2ffb2..574b2a91 100644 --- a/firmware/application/apps/ui_about_simple.cpp +++ b/firmware/application/apps/ui_about_simple.cpp @@ -34,6 +34,7 @@ void AboutView::update() { console.writeln("notpike,jLynx,zigad"); console.writeln("MichalLeonBorsuk,jimilinuxguy"); console.writeln("kallanreed,bernd-herzog"); + console.writeln("NotherNgineer,zxkmm,u-foka"); console.writeln(""); break; diff --git a/firmware/application/apps/ui_afsk_rx.cpp b/firmware/application/apps/ui_afsk_rx.cpp index c94768f0..45f6177c 100644 --- a/firmware/application/apps/ui_afsk_rx.cpp +++ b/firmware/application/apps/ui_afsk_rx.cpp @@ -55,6 +55,7 @@ AFSKRxView::AFSKRxView(NavigationView& nav) { &field_rf_amp, &field_lna, &field_vga, + &field_volume, &field_frequency, &check_log, &text_debug, diff --git a/firmware/application/apps/ui_afsk_rx.hpp b/firmware/application/apps/ui_afsk_rx.hpp index 848c4056..9673714b 100644 --- a/firmware/application/apps/ui_afsk_rx.hpp +++ b/firmware/application/apps/ui_afsk_rx.hpp @@ -79,6 +79,9 @@ class AFSKRxView : public View { {21 * 8, 5, 6 * 8, 4}, }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + FrequencyField field_frequency{ {0 * 8, 0 * 16}, }; diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index 1dd4a017..324b8f19 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -86,6 +86,7 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) &field_rf_amp, &field_lna, &field_vga, + &field_volume, &options_region, &field_frequency, &record_view, diff --git a/firmware/application/apps/ui_aprs_rx.hpp b/firmware/application/apps/ui_aprs_rx.hpp index b9f57794..2fc6b56a 100644 --- a/firmware/application/apps/ui_aprs_rx.hpp +++ b/firmware/application/apps/ui_aprs_rx.hpp @@ -207,6 +207,9 @@ class APRSRxView : public View { {21 * 8, 5, 6 * 8, 4}, }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + OptionsField options_region{ {0 * 8, 0 * 8}, 3, diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index d0adc22d..eba94a95 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -132,7 +132,7 @@ LevelView::LevelView(NavigationView& nav) audio::output::stop(); } else if (v == 1) { audio::output::start(); - receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // TODO: Needed? + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. } else { } }; diff --git a/firmware/application/apps/ui_playlist.cpp b/firmware/application/apps/ui_playlist.cpp index 6259f6aa..9a39be18 100644 --- a/firmware/application/apps/ui_playlist.cpp +++ b/firmware/application/apps/ui_playlist.cpp @@ -146,7 +146,7 @@ void PlaylistView::toggle() { track_number = 0; playlist_db.clear(); playlist_masterdb.clear(); - } else { // Thanks kallanreed for providing this logic! + } else { total_tracks = 0; track_number = 0; playlist_db.clear(); diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index c01e7bb3..d450e5d4 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -182,7 +182,6 @@ bool ReconView::recon_load_config_from_sd() { squelch = -14; recon_match_mode = RECON_MATCH_CONTINUOUS; wait = RECON_DEF_WAIT_DURATION; - volume = 40; return false; } @@ -221,11 +220,6 @@ bool ReconView::recon_load_config_from_sd() { else wait = RECON_DEF_WAIT_DURATION; - if (it > 7) - volume = strtoll(params[7].c_str(), nullptr, 10); - else - volume = 40; - return true; } @@ -244,13 +238,12 @@ bool ReconView::recon_save_config_to_sd() { settings_file.write_line(to_string_dec_int(squelch)); settings_file.write_line(to_string_dec_uint(recon_match_mode)); settings_file.write_line(to_string_dec_int(wait)); - settings_file.write_line(to_string_dec_int(volume)); return true; } void ReconView::audio_output_start() { audio::output::start(); - receiver_model.set_headphone_volume(receiver_model.headphone_volume()); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. } void ReconView::recon_redraw() { @@ -438,7 +431,6 @@ ReconView::ReconView(NavigationView& nav) load_ranges = persistent_memory::recon_load_ranges(); load_hamradios = persistent_memory::recon_load_hamradios(); update_ranges = persistent_memory::recon_update_ranges_when_recon(); - field_volume.set_value(volume); if (sd_card_mounted) { // load auto common app settings auto rc = settings.load("recon", &app_settings); diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index b594a672..85f706d4 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -149,7 +149,6 @@ class ReconView : public View { bool scanner_mode{false}; bool manual_mode{false}; bool sd_card_mounted = false; - int32_t volume = 40; int32_t stepper = 0; int32_t index_stepper = 0; int64_t freq = 0; diff --git a/firmware/application/apps/ui_recon_settings.hpp b/firmware/application/apps/ui_recon_settings.hpp index 626d8e33..c731d90e 100644 --- a/firmware/application/apps/ui_recon_settings.hpp +++ b/firmware/application/apps/ui_recon_settings.hpp @@ -60,7 +60,7 @@ //#define SCREEN_H 320 // recon settings nb params -#define RECON_SETTINGS_NB_PARAMS 8 +#define RECON_SETTINGS_NB_PARAMS 7 namespace ui { diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index bdf3152d..204615d9 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -119,15 +119,6 @@ void ReceiverModel::set_vga(int32_t v_db) { update_vga(); } -/*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(); -}*/ - uint32_t ReceiverModel::sampling_rate() const { return sampling_rate_; } @@ -147,20 +138,20 @@ void ReceiverModel::set_modulation(const Mode v) { } volume_t ReceiverModel::headphone_volume() const { - return headphone_volume_; + return persistent_memory::headphone_volume(); } void ReceiverModel::set_headphone_volume(volume_t v) { - headphone_volume_ = v; + persistent_memory::set_headphone_volume(v); update_headphone_volume(); } int32_t ReceiverModel::normalized_headphone_volume() const { - return (headphone_volume_ - audio::headphone::volume_range().max).decibel() + 99; + return (headphone_volume() - audio::headphone::volume_range().max).decibel() + 99; } void ReceiverModel::set_normalized_headphone_volume(int32_t v) { - // TODO: Linear map instead to ensure 0 is minimal value. + // TODO: Linear map instead to ensure 0 is minimal value or fix volume_range_t::normalize. v = clip(v, 0, 99); auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; set_headphone_volume(new_volume); @@ -183,13 +174,11 @@ void ReceiverModel::enable() { update_rf_amp(); update_lna(); update_vga(); - // update_tx_gain(); update_baseband_bandwidth(); update_sampling_rate(); update_modulation(); - // TODO: would challenge if this should belong to the - // receiver_model namespace: + // TODO: maybe not the perfect place for this, but it's reasonable. update_headphone_volume(); led_rx.on(); @@ -241,10 +230,6 @@ void ReceiverModel::update_vga() { radio::set_vga_gain(vga_gain_db_); } -/*void ReceiverModel::update_tx_gain() { - radio::set_tx_gain(tx_gain_db_); -}*/ - void ReceiverModel::set_am_configuration(const size_t n) { if (n < am_configs.size()) { am_config_index = n; @@ -277,7 +262,7 @@ void ReceiverModel::update_sampling_rate() { } void ReceiverModel::update_headphone_volume() { - audio::headphone::set_volume(headphone_volume_); + audio::headphone::set_volume(headphone_volume()); } void ReceiverModel::update_modulation() { diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index 26631c14..b5e4b661 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -61,10 +61,6 @@ class ReceiverModel { int32_t vga() const; void set_vga(int32_t v_db); - // TODO: Why does receiver need tx_gain? - // int32_t tx_gain() const; - // void set_tx_gain(int32_t v_db); - uint32_t sampling_rate() const; void set_sampling_rate(uint32_t v); @@ -108,13 +104,11 @@ class ReceiverModel { int32_t lna_gain_db_{32}; uint32_t baseband_bandwidth_{max283x::filter::bandwidth_minimum}; int32_t vga_gain_db_{32}; - // int32_t tx_gain_db_{47}; Mode mode_{Mode::NarrowbandFMAudio}; uint32_t sampling_rate_{3072000}; size_t am_config_index = 0; size_t nbfm_config_index = 0; size_t wfm_config_index = 0; - volume_t headphone_volume_{-43.0_dB}; uint8_t squelch_level_{80}; int32_t tuning_offset(); diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index b7445adb..bbff5c5c 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -22,6 +22,7 @@ #include "portapack_persistent_memory.hpp" +#include "audio.hpp" #include "portapack.hpp" #include "hal.h" @@ -75,7 +76,7 @@ constexpr clkout_freq_range_t clkout_freq_range{10, 60000}; constexpr uint32_t clkout_freq_reset_value{10000}; enum data_structure_version_enum : uint32_t { - VERSION_CURRENT = 0x10000002, + VERSION_CURRENT = 0x10000003, }; static const uint32_t TOUCH_CALIBRATION_MAGIC = 0x074af82f; @@ -305,6 +306,9 @@ struct data_t { // Rotary encoder dial sensitivity (encoder.cpp/hpp) uint8_t encoder_dial_sensitivity; + // Headphone volume in centibels. + int32_t headphone_volume_cb; + constexpr data_t() : structure_version(data_structure_version_enum::VERSION_CURRENT), tuned_frequency(tuned_frequency_reset_value), @@ -341,7 +345,8 @@ struct data_t { updown_frequency_rx_correction(0), frequency_tx_correction(0), updown_frequency_tx_correction(0), - encoder_dial_sensitivity(0) { + encoder_dial_sensitivity(0), + headphone_volume_cb(-600) { } }; @@ -423,6 +428,9 @@ namespace cache { void defaults() { cached_backup_ram = backup_ram_t(); + *data = data_t(); // This is a workaround for apparently alignment issue + // that is causing backup_ram_t's block copy to be + // misaligned. This force sets values through the struct. // defaults values for recon app set_recon_autosave_freqs(false); @@ -469,6 +477,17 @@ void set_tuned_frequency(const rf::Frequency new_value) { data->tuned_frequency = rf::tuning_range.clip(new_value); } +volume_t headphone_volume() { + auto volume = volume_t::centibel(data->headphone_volume_cb); + volume = audio::headphone::volume_range().limit(volume); + return volume; +} + +void set_headphone_volume(volume_t new_value) { + new_value = audio::headphone::volume_range().limit(new_value); + data->headphone_volume_cb = new_value.centibel(); +} + ppb_t correction_ppb() { ppb_range.reset_if_outside(data->correction_ppb, ppb_reset_value); return data->correction_ppb; diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 911fed7d..653025e3 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -31,6 +31,7 @@ #include "touch.hpp" #include "modems.hpp" #include "serializer.hpp" +#include "volume.hpp" // persistant memory from/to sdcard flag file #define PMEM_FILEFLAG "/SETTINGS/PMEM_FILEFLAG" @@ -132,6 +133,9 @@ using ppb_t = int32_t; rf::Frequency tuned_frequency(); void set_tuned_frequency(const rf::Frequency new_value); +volume_t headphone_volume(); +void set_headphone_volume(volume_t new_value); + ppb_t correction_ppb(); void set_correction_ppb(const ppb_t new_value); diff --git a/firmware/common/volume.hpp b/firmware/common/volume.hpp index 0c87f002..0b91e6c3 100644 --- a/firmware/common/volume.hpp +++ b/firmware/common/volume.hpp @@ -23,6 +23,7 @@ #define __VOLUME_H__ #include +#include "utility.hpp" class volume_t { public: @@ -89,13 +90,7 @@ struct volume_range_t { volume_t max; volume_t limit(const volume_t value) const { - if (value < min) { - return min; - } - if (value > max) { - return max; - } - return value; + return clip(value, min, max); } volume_t normalize(const volume_t value) const {