diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 90d2cefd..190de6a0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,12 +1,18 @@ --- name: Bug report -about: Create a report to help us improve +about: Create a report to help us improve the software title: '' labels: bug assignees: '' --- +---- + +(Please try the latest nightly release before submitting this. You can find the latest nightly verison here: https://github.com/eried/portapack-mayhem/releases) + +---- + **Describe the bug** A clear and concise description of what the bug is. @@ -21,9 +27,9 @@ A clear and concise description of what you expected to happen. **Affected versions** Please write any difference related with the Expected behavior, on the following versions: -* Latest Stable Release -* Previous one (if any) that did not presented the issue -* Old versions available here: https://github.com/eried/Research/tree/master/HackRF/PortaPack/old_legacy_firmware +* Latest Stable release: +* Latest Nightly release: +* Previous working release: **Additional** If the bug is difficult to explain, additionally to the text please include images and videos. diff --git a/.github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md b/.github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md index e3845184..9baba907 100644 --- a/.github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md +++ b/.github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md @@ -1,18 +1,39 @@ --- -name: Problem upgrading the firmware -about: Deal with the firmware upgrade problems -title: Problem upgrading the firmware -labels: '' +name: Problem upgrading the firmware or booting +about: If you are having firmware upgrade or booting problems +title: '' +labels: 'firmware' assignees: '' --- -**What is happening?** -Describe here why you are unable to upgrade the firmware. Before describing your problems, **do the following**: +---- +Before creating this issue, **do the following**: +* Read the Wiki on booting: https://github.com/eried/portapack-mayhem/wiki/Won't-boot * Read: https://github.com/eried/portapack-havoc/wiki/Update-firmware * Watch carefully: https://www.youtube.com/watch?v=_zx4ZvurgOs * (if you are not in Windows) also check: https://www.youtube.com/watch?v=kjFB58Y1TAo +---- + +**Describe the issue** +A clear and concise description of what the issue you are facing is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Tap on '....' + + +**My Hardware** +Please specify what PortaPack hardware version you are using. +You can find the list of versions here: https://github.com/eried/portapack-mayhem/wiki/PortaPack-Versions + +**Affected versions** +Please tell us what version you are running. +Also please try the latest nightly release before submitting this. +You can find the latest nightly version here https://github.com/eried/portapack-mayhem/releases + **Were you able to update the firmware before?** Things might be confusing the first time, please check the video available on the link above. @@ -20,4 +41,4 @@ Things might be confusing the first time, please check the video available on th If is possible, swap hardware and try again. Also, try different USB cables, even if the one you are using works fine for other purposes. **Additional** -Add photos and videos of your procedure. +If the issue is difficult to explain, additionally to the text please include images and videos. diff --git a/.github/workflows/create_stable_release.yml b/.github/workflows/create_stable_release.yml index 53c6e45e..30a74fdd 100644 --- a/.github/workflows/create_stable_release.yml +++ b/.github/workflows/create_stable_release.yml @@ -51,7 +51,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: v1.5.1 + tag_name: ${{ steps.version.outputs.version }} release_name: Mayhem firmware ${{ steps.version.outputs.version }} body: | **Stable release - ${{ steps.version.outputs.version }}** diff --git a/.github/workflows/past_version.txt b/.github/workflows/past_version.txt index 76864c1c..f1a2e631 100644 --- a/.github/workflows/past_version.txt +++ b/.github/workflows/past_version.txt @@ -1 +1 @@ -v1.5.0 \ No newline at end of file +v1.5.3 diff --git a/.github/workflows/version.txt b/.github/workflows/version.txt index c9b3c015..f074f24d 100644 --- a/.github/workflows/version.txt +++ b/.github/workflows/version.txt @@ -1 +1 @@ -v1.5.1 \ No newline at end of file +v1.5.4 diff --git a/.gitignore b/.gitignore index 06d8c0ab..c674d12d 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ # Compiled Dynamic libraries *.so *.dylib -*.dll # Fortran module files *.mod diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index a422aaaf..2def6164 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -154,6 +154,7 @@ set(CPPSRC ${COMMON}/ui_widget.cpp ${COMMON}/utility.cpp ${COMMON}/wm8731.cpp + app_settings.cpp audio.cpp baseband_api.cpp capture_thread.cpp diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp new file mode 100644 index 00000000..df93a20b --- /dev/null +++ b/firmware/application/app_settings.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * Copyright (C) 2022 Arjan Onwezen + * + * 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 "app_settings.hpp" + +#include "file.hpp" +#include "portapack.hpp" +#include "portapack_persistent_memory.hpp" +#include +#include + +namespace std { + +int app_settings::load(std::string application, AppSettings* settings) { + + if (portapack::persistent_memory::load_app_settings()) { + file_path = folder+"/"+application+".ini"; + + auto error = settings_file.open(file_path); + if (!error.is_valid()) { + auto error = settings_file.read(file_content, std::min((int)settings_file.size(), MAX_FILE_CONTENT_SIZE)); + + settings->baseband_bandwidth=std::app_settings::read_long_long(file_content, "baseband_bandwidth="); + settings->channel_bandwidth=std::app_settings::read_long_long(file_content, "channel_bandwidth="); + settings->lna=std::app_settings::read_long_long(file_content, "lna="); + settings->modulation=std::app_settings::read_long_long(file_content, "modulation="); + settings->rx_amp=std::app_settings::read_long_long(file_content, "rx_amp="); + settings->rx_frequency=std::app_settings::read_long_long(file_content, "rx_frequency="); + settings->sampling_rate=std::app_settings::read_long_long(file_content, "sampling_rate="); + settings->vga=std::app_settings::read_long_long(file_content, "vga="); + settings->tx_amp=std::app_settings::read_long_long(file_content, "tx_amp="); + settings->tx_frequency=std::app_settings::read_long_long(file_content, "tx_frequency="); + settings->tx_gain=std::app_settings::read_long_long(file_content, "tx_gain="); + rc = SETTINGS_OK; + } + else rc = SETTINGS_UNABLE_TO_LOAD; + } + else rc = SETTINGS_DISABLED; + return(rc); +} + +int app_settings::save(std::string application, AppSettings* settings) { + + if (portapack::persistent_memory::save_app_settings()) { + file_path = folder+"/"+application+".ini"; + make_new_directory(folder); + + auto error = settings_file.create(file_path); + if (!error.is_valid()) { + // Save common setting + settings_file.write_line("baseband_bandwidth="+to_string_dec_uint(portapack::receiver_model.baseband_bandwidth())); + settings_file.write_line("channel_bandwidth="+to_string_dec_uint(portapack::transmitter_model.channel_bandwidth())); + settings_file.write_line("lna="+to_string_dec_uint(portapack::receiver_model.lna())); + settings_file.write_line("rx_amp="+to_string_dec_uint(portapack::receiver_model.rf_amp())); + settings_file.write_line("sampling_rate="+to_string_dec_uint(portapack::receiver_model.sampling_rate())); + settings_file.write_line("tx_amp="+to_string_dec_uint(portapack::transmitter_model.rf_amp())); + settings_file.write_line("tx_gain="+to_string_dec_uint(portapack::transmitter_model.tx_gain())); + settings_file.write_line("vga="+to_string_dec_uint(portapack::receiver_model.vga())); + // Save other settings from struct + settings_file.write_line("rx_frequency="+to_string_dec_uint(settings->rx_frequency)); + settings_file.write_line("tx_frequency="+to_string_dec_uint(settings->tx_frequency)); + + rc = SETTINGS_OK; + } + else rc = SETTINGS_UNABLE_TO_SAVE; + } + else rc = SETTINGS_DISABLED; + return(rc); +} + + +long long int app_settings::read_long_long(char* file_content, const char* setting_text) { + auto position = strstr(file_content, (char *)setting_text); + if (position) { + position += strlen((char *)setting_text); + setting_value = strtoll(position, nullptr, 10); + } + return(setting_value); +} + + +} /* namespace std */ diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp new file mode 100644 index 00000000..9a877978 --- /dev/null +++ b/firmware/application/app_settings.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * Copyright (C) 2022 Arjan Onwezen + * + * 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. + */ + +#ifndef __APP_SETTINGS_H__ +#define __APP_SETTINGS_H__ + + +#include +#include +#include + +#include "file.hpp" +#include "string_format.hpp" + + +namespace std { +class app_settings { + + + +public: + +#define SETTINGS_OK 0 // settings found +#define SETTINGS_UNABLE_TO_LOAD -1 // settings (file) not found +#define SETTINGS_UNABLE_TO_SAVE -2 // unable to save settings +#define SETTINGS_DISABLED -3 // load/save settings disabled in settings + + + + struct AppSettings { + uint32_t baseband_bandwidth; + uint32_t channel_bandwidth; + uint8_t lna; + uint8_t modulation; + uint8_t rx_amp; + uint32_t rx_frequency; + uint32_t sampling_rate; + uint8_t tx_amp; + uint32_t tx_frequency; + uint8_t tx_gain; + uint8_t vga; + }; + + int load(std::string application, AppSettings* settings); + int save(std::string application, AppSettings* settings); + + +private: + +#define MAX_FILE_CONTENT_SIZE 1000 + + char file_content[MAX_FILE_CONTENT_SIZE] = {}; + std::string file_path = ""; + std::string folder = "SETTINGS"; + int rc = SETTINGS_OK; + File settings_file { }; + long long int setting_value {} ; + + long long int read_long_long(char* file_content, const char* setting_text); + + +}; // class app_settings +} // namespace std + + + +#endif/*__APP_SETTINGS_H__*/ diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp index a5c25a55..1561fee2 100644 --- a/firmware/application/apps/ais_app.cpp +++ b/firmware/application/apps/ais_app.cpp @@ -335,24 +335,23 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } { &recent_entry_detail_view, }); + + // load app settings + auto rc = settings.load("rx_ais", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + target_frequency_ = app_settings.rx_frequency; + } + else target_frequency_ = initial_target_frequency; + recent_entry_detail_view.hidden(true); - target_frequency_ = initial_target_frequency; - - receiver_model.set_tuning_frequency(tuning_frequency()); - receiver_model.set_sampling_rate(sampling_rate); - receiver_model.set_baseband_bandwidth(baseband_bandwidth); - receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias. - -/* radio::enable({ // this can be removed, previous version,no DC-bias control. - tuning_frequency(), - sampling_rate, - baseband_bandwidth, - rf::Direction::Receive, - receiver_model.rf_amp(), - static_cast(receiver_model.lna()), - static_cast(receiver_model.vga()), - }); */ + receiver_model.set_tuning_frequency(tuning_frequency()); + receiver_model.set_sampling_rate(sampling_rate); + receiver_model.set_baseband_bandwidth(baseband_bandwidth); + receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias. options_channel.on_change = [this](size_t, OptionsField::value_t v) { this->on_frequency_changed(v); @@ -373,7 +372,11 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } { } AISAppView::~AISAppView() { -/* radio::disable(); */ + + // save app settings + app_settings.rx_frequency = target_frequency_; + settings.save("rx_ais", &app_settings); + receiver_model.disable(); // to switch off all, including DC bias. baseband::shutdown(); diff --git a/firmware/application/apps/ais_app.hpp b/firmware/application/apps/ais_app.hpp index c7923049..6d319ba0 100644 --- a/firmware/application/apps/ais_app.hpp +++ b/firmware/application/apps/ais_app.hpp @@ -33,7 +33,7 @@ #include "event_m0.hpp" #include "log_file.hpp" - +#include "app_settings.hpp" #include "ais_packet.hpp" #include "lpc43xx_cpp.hpp" @@ -166,13 +166,18 @@ public: void focus() override; - std::string title() const override { return "AIS"; }; + std::string title() const override { return "AIS Boats RX"; }; private: static constexpr uint32_t initial_target_frequency = 162025000; static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; + + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + NavigationView& nav_; AISRecentEntries recent { }; diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 6c4dec74..422633da 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -129,10 +129,19 @@ AnalogAudioView::AnalogAudioView( &waterfall }); + // load app settings + auto rc = settings.load("rx_audio", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + receiver_model.set_rf_amp(app_settings.rx_amp); + field_frequency.set_value(app_settings.rx_frequency); + } + else field_frequency.set_value(receiver_model.tuning_frequency()); + //Filename Datetime and Frequency record_view.set_filename_date_frequency(true); - field_frequency.set_value(receiver_model.tuning_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { this->on_tuning_frequency_changed(f); @@ -160,6 +169,7 @@ AnalogAudioView::AnalogAudioView( const auto modulation = receiver_model.modulation(); options_modulation.set_by_value(toUType(modulation)); + options_modulation.on_change = [this](size_t, OptionsField::value_t v) { this->on_modulation_changed(static_cast(v)); }; @@ -183,7 +193,7 @@ AnalogAudioView::AnalogAudioView( audio::output::start(); update_modulation(static_cast(modulation)); - on_modulation_changed(static_cast(modulation)); + on_modulation_changed(static_cast(modulation)); } size_t AnalogAudioView::get_spec_bw_index() { @@ -210,6 +220,11 @@ void AnalogAudioView::set_spec_trigger(uint16_t trigger) { } AnalogAudioView::~AnalogAudioView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_audio", &app_settings); + // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do // both? audio::output::stop(); @@ -397,9 +412,6 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) { } } -/*void AnalogAudioView::squelched() { - if (exit_on_squelch) nav_.pop(); -}*/ void AnalogAudioView::handle_coded_squelch(const uint32_t value) { float diff, min_diff = value; diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index 8f62e237..fd6f5bc1 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -29,7 +29,7 @@ #include "ui_spectrum.hpp" #include "ui_record_view.hpp" #include "ui_font_fixed_8x16.hpp" - +#include "app_settings.hpp" #include "tone_key.hpp" @@ -143,7 +143,7 @@ public: void focus() override; - std::string title() const override { return "Analog audio"; }; + std::string title() const override { return "Audio RX"; }; size_t get_spec_bw_index(); void set_spec_bw(size_t index, uint32_t bw); @@ -154,6 +154,10 @@ public: private: static constexpr ui::Dim header_height = 3 * 16; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 }; const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 }; diff --git a/firmware/application/apps/analog_tv_app.cpp b/firmware/application/apps/analog_tv_app.cpp index b3710573..50a1cb20 100644 --- a/firmware/application/apps/analog_tv_app.cpp +++ b/firmware/application/apps/analog_tv_app.cpp @@ -57,7 +57,18 @@ AnalogTvView::AnalogTvView( &tv }); - field_frequency.set_value(receiver_model.tuning_frequency()); + + // load app settings + auto rc = settings.load("rx_tv", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + receiver_model.set_rf_amp(app_settings.rx_amp); + field_frequency.set_value(app_settings.rx_frequency); + } + else field_frequency.set_value(receiver_model.tuning_frequency()); + + field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { this->on_tuning_frequency_changed(f); @@ -106,12 +117,15 @@ AnalogTvView::AnalogTvView( } AnalogTvView::~AnalogTvView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_tv", &app_settings); + // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do // both? audio::output::stop(); - receiver_model.disable(); - baseband::shutdown(); } diff --git a/firmware/application/apps/analog_tv_app.hpp b/firmware/application/apps/analog_tv_app.hpp index 6f90a55c..def1c940 100644 --- a/firmware/application/apps/analog_tv_app.hpp +++ b/firmware/application/apps/analog_tv_app.hpp @@ -29,7 +29,7 @@ #include "ui_receiver.hpp" #include "ui_tv.hpp" #include "ui_record_view.hpp" - +#include "app_settings.hpp" #include "ui_font_fixed_8x16.hpp" #include "tone_key.hpp" @@ -53,11 +53,15 @@ public: void focus() override; - std::string title() const override { return "Analog TV"; }; + std::string title() const override { return "Analog TV RX"; }; private: static constexpr ui::Dim header_height = 3 * 16; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + const Rect options_view_rect { 0 * 8, 1 * 16, 30 * 8, 1 * 16 }; const Rect nbfm_view_rect { 0 * 8, 1 * 16, 18 * 8, 1 * 16 }; diff --git a/firmware/application/apps/ert_app.cpp b/firmware/application/apps/ert_app.cpp index 91b3e5e1..5ab68fa9 100644 --- a/firmware/application/apps/ert_app.cpp +++ b/firmware/application/apps/ert_app.cpp @@ -105,6 +105,15 @@ ERTAppView::ERTAppView(NavigationView&) { &recent_entries_view, }); + // load app settings + auto rc = settings.load("rx_ert", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + + radio::enable({ initial_target_frequency, sampling_rate, @@ -122,6 +131,10 @@ ERTAppView::ERTAppView(NavigationView&) { } ERTAppView::~ERTAppView() { + + // save app settings + settings.save("rx_ert", &app_settings); + radio::disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ert_app.hpp b/firmware/application/apps/ert_app.hpp index 14eb61c0..ea4e11c6 100644 --- a/firmware/application/apps/ert_app.hpp +++ b/firmware/application/apps/ert_app.hpp @@ -28,7 +28,7 @@ #include "ui_channel.hpp" #include "event_m0.hpp" - +#include "app_settings.hpp" #include "log_file.hpp" #include "ert_packet.hpp" @@ -125,12 +125,17 @@ public: void focus() override; - std::string title() const override { return "ERT"; }; + std::string title() const override { return "ERT Meter RX"; }; private: ERTRecentEntries recent { }; std::unique_ptr logger { }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + + const RecentEntriesColumns columns { { { "ID", 10 }, { "Tp", 2 }, diff --git a/firmware/application/apps/gps_sim_app.hpp b/firmware/application/apps/gps_sim_app.hpp index 34c7bb2d..b027eeec 100644 --- a/firmware/application/apps/gps_sim_app.hpp +++ b/firmware/application/apps/gps_sim_app.hpp @@ -44,7 +44,7 @@ public: void set_parent_rect(const Rect new_parent_rect) override; void focus() override; - std::string title() const override { return "GPS Simulator"; }; + std::string title() const override { return "GPS Sim TX"; }; private: NavigationView& nav_; diff --git a/firmware/application/apps/lge_app.cpp b/firmware/application/apps/lge_app.cpp index c1f4ea0f..ad3b6d0a 100644 --- a/firmware/application/apps/lge_app.cpp +++ b/firmware/application/apps/lge_app.cpp @@ -39,10 +39,14 @@ using namespace portapack; namespace ui { void LGEView::focus() { - options_trame.focus(); + options_frame.focus(); } LGEView::~LGEView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_lge", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -70,10 +74,10 @@ void LGEView::generate_frame_touche() { std::vector data { 0x46, 0x28, 0x01, 0x45, 0x27, 0x01, 0x44, 0x23 }; console.write("\n\x1B\x07Touche:\x1B\x10"); - generate_lge_frame(0x96, (field_joueur.value() << 8) | field_salle.value(), 0x0001, data); + generate_lge_frame(0x96, (field_player.value() << 8) | field_room.value(), 0x0001, data); } -void LGEView::generate_frame_pseudo() { +void LGEView::generate_frame_nickname() { // 0040.48s: // 30 02 1A 00 19 00 FF 00 02 19 42 52 45 42 49 53 20 00 00 00 00 00 00 00 00 00 // 04 01 B0 04 7F 1F 11 33 40 1F 22 01 07 00 00 01 07 00 00 63 05 00 00 99 A2 @@ -90,15 +94,15 @@ void LGEView::generate_frame_pseudo() { }; uint32_t c; - //data_header[2] = field_salle.value(); // ? - //data_footer[0] = field_salle.value(); // ? + //data_header[2] = field_room.value(); // ? + //data_footer[0] = field_room.value(); // ? data.insert(data.begin(), data_header.begin(), data_header.end()); - data.push_back(field_joueur.value()); + data.push_back(field_player.value()); c = 0; - for (auto &ch : pseudo) { + for (auto &ch : nickname) { data.push_back(ch); c++; } @@ -108,16 +112,16 @@ void LGEView::generate_frame_pseudo() { while (++c < 16) data.push_back(0x00); - data.push_back(field_equipe.value()); + data.push_back(field_team.value()); data.insert(data.end(), data_footer.begin(), data_footer.end()); - console.write("\n\x1B\x0ESet pseudo:\x1B\x10"); + console.write("\n\x1B\x0ESet nickname:\x1B\x10"); - generate_lge_frame(0x02, 0x001A, field_joueur.value(), data); + generate_lge_frame(0x02, 0x001A, field_player.value(), data); } -void LGEView::generate_frame_equipe() { +void LGEView::generate_frame_team() { // 0041.83s: // 3D 03 FF FF FF FF 02 03 01 52 4F 55 47 45 00 00 00 00 00 00 00 00 00 00 00 00 // 02 56 45 52 54 45 00 00 00 00 00 00 00 00 00 00 00 01 03 42 4C 45 55 45 00 00 @@ -129,10 +133,10 @@ void LGEView::generate_frame_equipe() { data.insert(data.begin(), data_header.begin(), data_header.end()); - data.push_back(field_equipe.value()); + data.push_back(field_team.value()); c = 0; - for (auto &ch : pseudo) { + for (auto &ch : nickname) { data.push_back(ch); c++; } @@ -140,14 +144,14 @@ void LGEView::generate_frame_equipe() { while (c++ < 16) data.push_back(0x00); - data.push_back(field_equipe.value() - 1); // Color ? + data.push_back(field_team.value() - 1); // Color ? - console.write("\n\x1B\x0ASet equipe:\x1B\x10"); + console.write("\n\x1B\x0ASet team:\x1B\x10"); generate_lge_frame(0x03, data); } -void LGEView::generate_frame_broadcast_pseudo() { +void LGEView::generate_frame_broadcast_nickname() { // 0043.86s: // 3D 04 FF FF FF FF 02 03 19 42 52 45 42 49 53 20 00 00 00 00 00 00 00 00 00 04 // 07 50 4F 4E 45 59 20 00 00 00 00 00 00 00 00 00 00 05 1B 41 42 42 59 20 00 00 @@ -159,10 +163,10 @@ void LGEView::generate_frame_broadcast_pseudo() { data.insert(data.begin(), data_header.begin(), data_header.end()); - data.push_back(field_joueur.value()); + data.push_back(field_player.value()); c = 0; - for (auto &ch : pseudo) { + for (auto &ch : nickname) { data.push_back(ch); c++; } @@ -172,9 +176,9 @@ void LGEView::generate_frame_broadcast_pseudo() { while (++c < 16) data.push_back(0x00); - data.push_back(field_equipe.value()); + data.push_back(field_team.value()); - console.write("\n\x1B\x09" "Broadcast pseudo:\x1B\x10"); + console.write("\n\x1B\x09" "Broadcast nickname:\x1B\x10"); generate_lge_frame(0x04, data); } @@ -184,14 +188,14 @@ void LGEView::generate_frame_start() { // 0A 05 FF FF FF FF 02 EC FF FF FF A3 35 std::vector data { 0x02, 0xEC, 0xFF, 0xFF, 0xFF }; - //data[0] = field_salle.value(); // ? + //data[0] = field_room.value(); // ? console.write("\n\x1B\x0DStart:\x1B\x10"); generate_lge_frame(0x05, data); } void LGEView::generate_frame_gameover() { - std::vector data { (uint8_t)field_salle.value() }; + std::vector data { (uint8_t)field_room.value() }; console.write("\n\x1B\x0CGameover:\x1B\x10"); generate_lge_frame(0x0D, data); @@ -203,7 +207,7 @@ void LGEView::generate_frame_collier() { // Custom // 0C 00 13 37 13 37 id flags channel playerid zapduty zaptime checksum CRC CRC // channel: field_channel - // playerid: field_joueur + // playerid: field_player // zapduty: field_power // zaptime: field_duration @@ -218,8 +222,8 @@ void LGEView::generate_frame_collier() { std::vector data { id, flags, - (uint8_t)field_salle.value(), - (uint8_t)field_joueur.value(), + (uint8_t)field_room.value(), + (uint8_t)field_player.value(), (uint8_t)field_power.value(), (uint8_t)(field_duration.value() * 10) }; @@ -285,11 +289,11 @@ LGEView::LGEView(NavigationView& nav) { add_children({ &labels, - &options_trame, - &field_salle, - &button_texte, - &field_equipe, - &field_joueur, + &options_frame, + &field_room, + &button_text, + &field_team, + &field_player, &field_id, &field_power, &field_duration, @@ -300,20 +304,29 @@ LGEView::LGEView(NavigationView& nav) { &tx_view }); - field_salle.set_value(1); - field_equipe.set_value(1); - field_joueur.set_value(1); + // load app settings + auto rc = settings.load("tx_lge", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + + field_room.set_value(1); + field_team.set_value(1); + field_player.set_value(1); field_id.set_value(1); field_power.set_value(1); field_duration.set_value(2); - button_texte.on_select = [this, &nav](Button&) { + button_text.on_select = [this, &nav](Button&) { text_prompt( nav, - pseudo, + nickname, 15, [this](std::string& buffer) { - button_texte.set_text(buffer); + button_text.set_text(buffer); }); }; @@ -326,15 +339,15 @@ LGEView::LGEView(NavigationView& nav) { tx_view.on_start = [this]() { if (tx_mode == IDLE) { - auto i = options_trame.selected_index_value(); + auto i = options_frame.selected_index_value(); if (i == 0) generate_frame_touche(); else if (i == 1) - generate_frame_pseudo(); + generate_frame_nickname(); else if (i == 2) - generate_frame_equipe(); + generate_frame_team(); else if (i == 3) - generate_frame_broadcast_pseudo(); + generate_frame_broadcast_nickname(); else if (i == 4) generate_frame_start(); else if (i == 5) diff --git a/firmware/application/apps/lge_app.hpp b/firmware/application/apps/lge_app.hpp index 81825800..75377b29 100644 --- a/firmware/application/apps/lge_app.hpp +++ b/firmware/application/apps/lge_app.hpp @@ -30,6 +30,7 @@ #include "message.hpp" #include "transmitter_model.hpp" #include "portapack.hpp" +#include "app_settings.hpp" namespace ui { @@ -40,7 +41,7 @@ public: void focus() override; - std::string title() const override { return "LGE tool"; }; + std::string title() const override { return "LGE tool TX"; }; private: enum tx_modes { @@ -48,15 +49,19 @@ private: SINGLE, ALL }; + + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; tx_modes tx_mode = IDLE; - RFM69 rfm69 { 5, 0x2DD4, true, true }; + RFM69 rfm69 { 5, 0x2DD4, true, true }; uint32_t frame_size { 0 }; uint32_t repeats { 0 }; uint32_t channel_index { 0 }; - std::string pseudo { "ABCDEF" }; + std::string nickname { "ABCDEF" }; rf::Frequency channels[3] = { 868067000, 868183000, 868295000 }; @@ -68,9 +73,9 @@ private: } void generate_lge_frame(const uint8_t command, const uint16_t address_a, const uint16_t address_b, std::vector& data); void generate_frame_touche(); - void generate_frame_pseudo(); - void generate_frame_equipe(); - void generate_frame_broadcast_pseudo(); + void generate_frame_nickname(); + void generate_frame_team(); + void generate_frame_broadcast_nickname(); void generate_frame_start(); void generate_frame_gameover(); void generate_frame_collier(); @@ -79,28 +84,28 @@ private: Labels labels { //{ { 7 * 8, 1 * 8 }, "NO FUN ALLOWED !", Color::red() }, - { { 1 * 8, 1 * 8 }, "Trame:", Color::light_grey() }, - { { 1 * 8, 3 * 8 }, "Salle:", Color::light_grey() }, - { { 14 * 8, 3 * 8 }, "Texte:", Color::light_grey() }, - { { 0 * 8, 5 * 8 }, "Equipe:", Color::light_grey() }, - { { 0 * 8, 7 * 8 }, "Joueur:", Color::light_grey() }, - { { 0 * 8, 10 * 8 }, "Collier:", Color::light_grey() }, + { { 1 * 8, 1 * 8 }, "Frame:", Color::light_grey() }, + { { 2 * 8, 3 * 8 }, "Room:", Color::light_grey() }, + { { 14 * 8, 3 * 8 }, "Text:", Color::light_grey() }, + { { 2 * 8, 5 * 8 }, "Team:", Color::light_grey() }, + { { 0 * 8, 7 * 8 }, "Player:", Color::light_grey() }, + { { 0 * 8, 10 * 8 }, "Vest:", Color::light_grey() }, { { 4 * 8, 12 * 8 }, "ID:", Color::light_grey() }, { { 3 * 8, 14 * 8 }, "Pow: /10", Color::light_grey() }, - { { 1 * 8, 16 * 8 }, "Duree: x100ms", Color::light_grey() } + { { 2 * 8, 16 * 8 }, "Time: x100ms", Color::light_grey() } }; - OptionsField options_trame { + OptionsField options_frame { { 7 * 8, 1 * 8 }, 13, { - { "Touche", 0 }, - { "Set pseudo", 1 }, - { "Set equipe", 2 }, - { "Brdcst pseudo", 3 }, + { "Key", 0 }, + { "Set nickname", 1 }, + { "Set team", 2 }, + { "Brdcst nick", 3 }, { "Start", 4 }, { "Game over", 5 }, - { "Set collier", 6 } + { "Set vest", 6 } } }; @@ -111,7 +116,7 @@ private: true }; - NumberField field_salle { + NumberField field_room { { 7 * 8, 3 * 8 }, 1, { 1, 2 }, @@ -119,12 +124,12 @@ private: '0' }; - Button button_texte { + Button button_text { { 14 * 8, 5 * 8, 16 * 8, 3 * 8 }, "ABCDEF" }; - NumberField field_equipe { + NumberField field_team { { 7 * 8, 5 * 8 }, 1, { 1, 6 }, @@ -132,7 +137,7 @@ private: '0' }; - NumberField field_joueur { + NumberField field_player { { 7 * 8, 7 * 8 }, 2, { 1, 50 }, diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index cb5cacfe..d1dcb6b4 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -77,11 +77,22 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { &console }); + // load app settings + auto rc = settings.load("rx_pocsag", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + field_frequency.set_value(app_settings.rx_frequency); + } + else field_frequency.set_value(receiver_model.tuning_frequency()); + + receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); + receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); receiver_model.enable(); - field_frequency.set_value(receiver_model.tuning_frequency()); field_frequency.set_step(receiver_model.frequency_step()); field_frequency.on_change = [this](rf::Frequency f) { update_freq(f); @@ -127,6 +138,11 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { } POCSAGAppView::~POCSAGAppView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_pocsag", &app_settings); + audio::output::stop(); // Save ignored address diff --git a/firmware/application/apps/pocsag_app.hpp b/firmware/application/apps/pocsag_app.hpp index b917926c..8ea3c4b9 100644 --- a/firmware/application/apps/pocsag_app.hpp +++ b/firmware/application/apps/pocsag_app.hpp @@ -28,7 +28,7 @@ #include "ui_rssi.hpp" #include "log_file.hpp" - +#include "app_settings.hpp" #include "pocsag.hpp" #include "pocsag_packet.hpp" @@ -60,6 +60,10 @@ public: private: static constexpr uint32_t initial_target_frequency = 466175000; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + bool logging { true }; bool ignore { true }; uint32_t last_address = 0xFFFFFFFF; diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp index 9147c46f..4313b8e7 100644 --- a/firmware/application/apps/replay_app.cpp +++ b/firmware/application/apps/replay_app.cpp @@ -201,6 +201,16 @@ ReplayAppView::ReplayAppView( tx_gain = 35;field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ). field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's) + field_rfamp.on_change = [this](int32_t v) { // allow initial value change just after opened file. + rf_amp = (bool)v; + }; + field_rfamp.set_value(rf_amp ? 14 : 0); + + field_rfgain.on_change = [this](int32_t v) { // allow initial value change just after opened file. + tx_gain = v; + }; + field_rfgain.set_value(tx_gain); + baseband::run_image(portapack::spi_flash::image_tag_replay); add_children({ diff --git a/firmware/application/apps/soundboard_app.cpp b/firmware/application/apps/soundboard_app.cpp index 2c93822f..97e6ad70 100644 --- a/firmware/application/apps/soundboard_app.cpp +++ b/firmware/application/apps/soundboard_app.cpp @@ -240,6 +240,15 @@ SoundBoardView::SoundBoardView( &button_next_page, &tx_view }); + + // load app settings + auto rc = settings.load("tx_soundboard", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } refresh_list(); @@ -280,6 +289,10 @@ SoundBoardView::SoundBoardView( } SoundBoardView::~SoundBoardView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_soundboard", &app_settings); + stop(); transmitter_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/soundboard_app.hpp b/firmware/application/apps/soundboard_app.hpp index 91feaf96..a8afb73c 100644 --- a/firmware/application/apps/soundboard_app.hpp +++ b/firmware/application/apps/soundboard_app.hpp @@ -30,6 +30,7 @@ #include "lfsr_random.hpp" #include "io_wave.hpp" #include "tone_key.hpp" +#include "app_settings.hpp" namespace ui { @@ -45,10 +46,14 @@ public: void focus() override; - std::string title() const override { return "Soundboard"; }; + std::string title() const override { return "Soundboard TX"; }; private: NavigationView& nav_; + + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; enum tx_modes { NORMAL = 0, diff --git a/firmware/application/apps/tpms_app.cpp b/firmware/application/apps/tpms_app.cpp index 7858d7a2..69e137e9 100644 --- a/firmware/application/apps/tpms_app.cpp +++ b/firmware/application/apps/tpms_app.cpp @@ -151,6 +151,16 @@ TPMSAppView::TPMSAppView(NavigationView&) { &options_type, }); + // load app settings + auto rc = settings.load("rx_tpms", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + options_band.set_by_value(app_settings.rx_frequency); + } + else options_band.set_by_value(receiver_model.tuning_frequency()); + radio::enable({ tuning_frequency(), sampling_rate, @@ -184,6 +194,12 @@ TPMSAppView::TPMSAppView(NavigationView&) { } TPMSAppView::~TPMSAppView() { + + + // save app settings + app_settings.rx_frequency = target_frequency_; + settings.save("rx_tpms", &app_settings); + radio::disable(); baseband::shutdown(); diff --git a/firmware/application/apps/tpms_app.hpp b/firmware/application/apps/tpms_app.hpp index 7ccef644..9544554f 100644 --- a/firmware/application/apps/tpms_app.hpp +++ b/firmware/application/apps/tpms_app.hpp @@ -27,7 +27,7 @@ #include "ui_receiver.hpp" #include "ui_rssi.hpp" #include "ui_channel.hpp" - +#include "app_settings.hpp" #include "event_m0.hpp" #include "log_file.hpp" @@ -103,13 +103,17 @@ public: void focus() override; - std::string title() const override { return "TPMS"; }; + std::string title() const override { return "TPMS Cars RX"; }; private: static constexpr uint32_t initial_target_frequency = 315000000; static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + MessageHandlerRegistration message_handler_packet { Message::ID::TPMSPacket, [this](Message* const p) { diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index 1731061f..1ae332ee 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -309,8 +309,12 @@ void ADSBRxView::focus() { } ADSBRxView::~ADSBRxView() { - receiver_model.set_tuning_frequency(prevFreq); + // save app settings + settings.save("rx_adsb", &app_settings); + + //TODO: once all apps keep there own settin previous frequency logic can be removed + receiver_model.set_tuning_frequency(prevFreq); rtc_time::signal_tick_second -= signal_token_tick_second; receiver_model.disable(); baseband::shutdown(); @@ -458,6 +462,21 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { &recent_entries_view }); + + // load app settings + auto rc = settings.load("rx_adsb", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + else + { + field_lna.set_value(40); + field_vga.set_value(40); + } + + recent_entries_view.set_parent_rect({ 0, 16, 240, 272 }); recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) { detailed_entry_key = entry.key(); @@ -478,8 +497,6 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { baseband::set_adsb(); receiver_model.set_tuning_frequency(1090000000); - field_lna.set_value(40); - field_vga.set_value(40); receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis); receiver_model.set_sampling_rate(2000000); receiver_model.set_baseband_bandwidth(2500000); diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index 36e1a190..e882b8db 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -32,7 +32,7 @@ #include "log_file.hpp" #include "adsb.hpp" #include "message.hpp" - +#include "app_settings.hpp" #include "crc.hpp" using namespace adsb; @@ -361,7 +361,7 @@ public: void focus() override; - std::string title() const override { return "ADS-B receive"; }; + std::string title() const override { return "ADS-B RX"; }; void replace_entry(AircraftRecentEntry & entry); AircraftRecentEntry find_or_create_entry(uint32_t ICAO_address); @@ -372,6 +372,9 @@ private: std::unique_ptr logger { }; void on_frame(const ADSBFrameMessage * message); void on_tick_second(); + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; const RecentEntriesColumns columns { { #if false diff --git a/firmware/application/apps/ui_adsb_tx.cpp b/firmware/application/apps/ui_adsb_tx.cpp index 198d2295..918e744c 100644 --- a/firmware/application/apps/ui_adsb_tx.cpp +++ b/firmware/application/apps/ui_adsb_tx.cpp @@ -284,6 +284,11 @@ void ADSBTxView::focus() { } ADSBTxView::~ADSBTxView() { + + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_adsb", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -334,8 +339,16 @@ ADSBTxView::ADSBTxView( &view_squawk, &text_frame, &tx_view - }); - + }); + + // load app settings + auto rc = settings.load("tx_adsb", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + tx_view.on_edit_frequency = [this, &nav]() { auto new_view = nav.push(receiver_model.tuning_frequency()); new_view->on_changed = [this](rf::Frequency f) { diff --git a/firmware/application/apps/ui_adsb_tx.hpp b/firmware/application/apps/ui_adsb_tx.hpp index f68da241..8556f6e8 100644 --- a/firmware/application/apps/ui_adsb_tx.hpp +++ b/firmware/application/apps/ui_adsb_tx.hpp @@ -28,6 +28,7 @@ #include "ui_transmitter.hpp" #include "message.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" #include "portapack.hpp" using namespace adsb; @@ -152,7 +153,7 @@ public: void focus() override; - std::string title() const override { return "ADS-B transmit"; }; + std::string title() const override { return "ADS-B TX"; }; private: /*enum tx_modes { @@ -189,6 +190,10 @@ private: -1, -1 };*/ + + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; //tx_modes tx_mode = IDLE; NavigationView& nav_; diff --git a/firmware/application/apps/ui_afsk_rx.cpp b/firmware/application/apps/ui_afsk_rx.cpp index 4b8fc3e7..54792f57 100644 --- a/firmware/application/apps/ui_afsk_rx.cpp +++ b/firmware/application/apps/ui_afsk_rx.cpp @@ -66,6 +66,15 @@ AFSKRxView::AFSKRxView(NavigationView& nav) { &console }); + // load app settings + auto rc = settings.load("rx_afsk", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + + // DEBUG record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); @@ -164,6 +173,11 @@ void AFSKRxView::on_data(uint32_t value, bool is_data) { } AFSKRxView::~AFSKRxView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_afsk", &app_settings); + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_afsk_rx.hpp b/firmware/application/apps/ui_afsk_rx.hpp index 86f0f28f..dccf0e01 100644 --- a/firmware/application/apps/ui_afsk_rx.hpp +++ b/firmware/application/apps/ui_afsk_rx.hpp @@ -27,7 +27,7 @@ #include "ui_navigation.hpp" #include "ui_receiver.hpp" #include "ui_record_view.hpp" // DEBUG - +#include "app_settings.hpp" #include "log_file.hpp" #include "utility.hpp" @@ -57,6 +57,10 @@ public: private: void on_data(uint32_t value, bool is_data); + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + uint8_t console_color { 0 }; uint32_t prev_value { 0 }; std::string str_log { "" }; diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index 1bcfd273..c1f16893 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -98,6 +98,15 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) : View(parent_rect &console }); + // load app settings + auto rc = settings.load("rx_aprs", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + + // DEBUG record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); @@ -211,6 +220,10 @@ void APRSRxView::on_show(){ } APRSRxView::~APRSRxView() { + + // save app settings + settings.save("rx_aprs", &app_settings); + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_aprs_rx.hpp b/firmware/application/apps/ui_aprs_rx.hpp index 9ea29559..1a37df92 100644 --- a/firmware/application/apps/ui_aprs_rx.hpp +++ b/firmware/application/apps/ui_aprs_rx.hpp @@ -28,7 +28,7 @@ #include "ui_receiver.hpp" #include "ui_record_view.hpp" // DEBUG #include "ui_geomap.hpp" - +#include "app_settings.hpp" #include "recent_entries.hpp" #include "ui_tabview.hpp" @@ -131,6 +131,7 @@ private: GeoMapView* geomap_view { nullptr }; bool send_updates { false }; + Console console { { 0, 0 * 16, 240, 224 } }; @@ -192,6 +193,11 @@ private: void on_data(uint32_t value, bool is_data); bool reset_console = false; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + + uint8_t console_color { 0 }; std::string str_log { "" }; diff --git a/firmware/application/apps/ui_aprs_tx.cpp b/firmware/application/apps/ui_aprs_tx.cpp index 87ff6927..5d275931 100644 --- a/firmware/application/apps/ui_aprs_tx.cpp +++ b/firmware/application/apps/ui_aprs_tx.cpp @@ -43,6 +43,10 @@ void APRSTXView::focus() { } APRSTXView::~APRSTXView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_aprs", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -66,7 +70,7 @@ void APRSTXView::start_tx() { 1200, 2200, 1, - 10000, //transmitter_model.channel_bandwidth(), + 10000, //APRS uses fixed 10k bandwidth 8 ); } @@ -95,6 +99,15 @@ APRSTXView::APRSTXView(NavigationView& nav) { &tx_view }); + + // load app settings + auto rc = settings.load("tx_aprs", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + button_set.on_select = [this, &nav](Button&) { text_prompt( nav, diff --git a/firmware/application/apps/ui_aprs_tx.hpp b/firmware/application/apps/ui_aprs_tx.hpp index 97032107..16872b11 100644 --- a/firmware/application/apps/ui_aprs_tx.hpp +++ b/firmware/application/apps/ui_aprs_tx.hpp @@ -29,6 +29,7 @@ #include "message.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" #include "portapack.hpp" namespace ui { @@ -40,17 +41,14 @@ public: void focus() override; - std::string title() const override { return "APRS TX (beta)"; }; + std::string title() const override { return "APRS TX"; }; private: - /*enum tx_modes { - IDLE = 0, - SINGLE, - SEQUENCE - }; - - tx_modes tx_mode = IDLE;*/ + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + std::string payload { "" }; void start_tx(); @@ -103,7 +101,7 @@ private: TransmitterView tx_view { 16 * 16, 5000, - 10 + 0 // disable setting bandwith, since APRS used fixed 10k bandwidth }; MessageHandlerRegistration message_handler_tx_progress { diff --git a/firmware/application/apps/ui_bht_tx.cpp b/firmware/application/apps/ui_bht_tx.cpp index 6021a240..b70f4d17 100644 --- a/firmware/application/apps/ui_bht_tx.cpp +++ b/firmware/application/apps/ui_bht_tx.cpp @@ -96,9 +96,9 @@ void BHTView::on_tx_progress(const uint32_t progress, const bool done) { if (target_system == XYLOS) { if (done) { if (tx_mode == SINGLE) { - if (checkbox_cligno.value()) { + if (checkbox_flashing.value()) { // TODO: Thread ! - chThdSleepMilliseconds(field_tempo.value() * 1000); // Dirty :( + chThdSleepMilliseconds(field_speed.value() * 1000); // Dirty :( view_xylos.flip_relays(); start_tx(); } else @@ -120,9 +120,9 @@ void BHTView::on_tx_progress(const uint32_t progress, const bool done) { } else { view_EPAR.half = false; if (tx_mode == SINGLE) { - if (checkbox_cligno.value()) { + if (checkbox_flashing.value()) { // TODO: Thread ! - chThdSleepMilliseconds(field_tempo.value() * 1000); // Dirty :( + chThdSleepMilliseconds(field_speed.value() * 1000); // Dirty :( view_EPAR.flip_relays(); start_tx(); } else @@ -140,6 +140,10 @@ void BHTView::on_tx_progress(const uint32_t progress, const bool done) { } BHTView::~BHTView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_bht", &app_settings); + transmitter_model.disable(); } @@ -150,13 +154,22 @@ BHTView::BHTView(NavigationView& nav) { &view_xylos, &view_EPAR, &checkbox_scan, - &checkbox_cligno, - &field_tempo, + &checkbox_flashing, + &field_speed, &progressbar, &tx_view }); - field_tempo.set_value(1); + // load app settings + auto rc = settings.load("tx_bht", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + + field_speed.set_value(1); tx_view.on_edit_frequency = [this, &nav]() { auto new_view = nav.push(receiver_model.tuning_frequency()); diff --git a/firmware/application/apps/ui_bht_tx.hpp b/firmware/application/apps/ui_bht_tx.hpp index 64cf838d..17768e2b 100644 --- a/firmware/application/apps/ui_bht_tx.hpp +++ b/firmware/application/apps/ui_bht_tx.hpp @@ -32,6 +32,7 @@ #include "message.hpp" #include "transmitter_model.hpp" #include "encoders.hpp" +#include "app_settings.hpp" #include "portapack.hpp" namespace ui { @@ -50,11 +51,11 @@ public: private: Labels labels { { { 8 * 8, 1 * 8 }, "Header:", Color::light_grey() }, - { { 4 * 8, 3 * 8 }, "Code ville:", Color::light_grey() }, - { { 7 * 8, 5 * 8 }, "Famille:", Color::light_grey() }, - { { 2 * 8, 7 * 8 + 2 }, "Sous-famille:", Color::light_grey() }, - { { 2 * 8, 11 * 8 }, "ID recepteur:", Color::light_grey() }, - { { 2 * 8, 14 * 8 }, "Relais:", Color::light_grey() } + { { 4 * 8, 3 * 8 }, "City code:", Color::light_grey() }, + { { 7 * 8, 5 * 8 }, "Family:", Color::light_grey() }, + { { 2 * 8, 7 * 8 + 2 }, "Subfamily:", Color::light_grey() }, + { { 2 * 8, 11 * 8 }, "Receiver ID:", Color::light_grey() }, + { { 2 * 8, 14 * 8 }, "Relay:", Color::light_grey() } }; NumberField field_header_a { @@ -98,8 +99,8 @@ private: Checkbox checkbox_wcsubfamily { { 20 * 8, 6 * 8 + 6 }, - 6, - "Toutes" + 3, + "All" }; NumberField field_receiver { @@ -111,8 +112,8 @@ private: }; Checkbox checkbox_wcid { { 20 * 8, 10 * 8 + 4 }, - 4, - "Tous" + 3, + "All" }; std::array relay_states { }; @@ -139,9 +140,9 @@ public: private: Labels labels { - { { 4 * 8, 1 * 8 }, "Code ville:", Color::light_grey() }, - { { 8 * 8, 3 * 8 }, "Groupe:", Color::light_grey() }, - { { 8 * 8, 7 * 8 }, "Relais:", Color::light_grey() } + { { 4 * 8, 1 * 8 }, "City code:", Color::light_grey() }, + { { 8 * 8, 3 * 8 }, "Group:", Color::light_grey() }, + { { 8 * 8, 7 * 8 }, "Relay:", Color::light_grey() } }; NumberField field_city { @@ -178,9 +179,13 @@ public: void focus() override; - std::string title() const override { return "BHT transmit"; }; + std::string title() const override { return "BHT Xy/EP TX"; }; private: + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + void on_tx_progress(const uint32_t progress, const bool done); void start_tx(); void stop_tx(); @@ -220,12 +225,12 @@ private: "Scan" }; - Checkbox checkbox_cligno { + Checkbox checkbox_flashing { { 16 * 8, 25 * 8 }, - 6, - "Cligno" + 8, + "Flashing" }; - NumberField field_tempo { + NumberField field_speed { { 26 * 8, 25 * 8 + 4 }, 2, { 1, 99 }, diff --git a/firmware/application/apps/ui_btle_rx.cpp b/firmware/application/apps/ui_btle_rx.cpp index d4b9afee..226f9dc1 100644 --- a/firmware/application/apps/ui_btle_rx.cpp +++ b/firmware/application/apps/ui_btle_rx.cpp @@ -60,6 +60,15 @@ BTLERxView::BTLERxView(NavigationView& nav) { &console }); + // load app settings + auto rc = settings.load("rx_btle", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + + // DEBUG record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); @@ -152,6 +161,11 @@ void BTLERxView::on_data(uint32_t value, bool is_data) { } BTLERxView::~BTLERxView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_btle", &app_settings); + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_btle_rx.hpp b/firmware/application/apps/ui_btle_rx.hpp index 9e331eef..91bf0710 100644 --- a/firmware/application/apps/ui_btle_rx.hpp +++ b/firmware/application/apps/ui_btle_rx.hpp @@ -27,6 +27,7 @@ #include "ui.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" +#include "app_settings.hpp" #include "ui_record_view.hpp" // DEBUG #include "utility.hpp" @@ -45,6 +46,11 @@ public: private: void on_data(uint32_t value, bool is_data); + + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + uint8_t console_color { 0 }; uint32_t prev_value { 0 }; std::string str_log { "" }; diff --git a/firmware/application/apps/ui_coasterp.cpp b/firmware/application/apps/ui_coasterp.cpp index cd918dda..446ad841 100644 --- a/firmware/application/apps/ui_coasterp.cpp +++ b/firmware/application/apps/ui_coasterp.cpp @@ -37,6 +37,10 @@ void CoasterPagerView::focus() { } CoasterPagerView::~CoasterPagerView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_coaster", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -119,6 +123,15 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) { &tx_view }); + // load app settings + auto rc = settings.load("tx_coaster", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + // Bytes to nibbles for (c = 0; c < 16; c++) sym_data.set_sym(c, (data_init[c >> 1] >> ((c & 1) ? 0 : 4)) & 0x0F); diff --git a/firmware/application/apps/ui_coasterp.hpp b/firmware/application/apps/ui_coasterp.hpp index 8d169d86..873d3abe 100644 --- a/firmware/application/apps/ui_coasterp.hpp +++ b/firmware/application/apps/ui_coasterp.hpp @@ -28,6 +28,7 @@ #include "message.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" #include "portapack.hpp" namespace ui { @@ -39,7 +40,7 @@ public: void focus() override; - std::string title() const override { return "Si44xx TX"; }; + std::string title() const override { return "BurgerPgr TX"; }; private: enum tx_modes { @@ -50,6 +51,10 @@ private: tx_modes tx_mode = IDLE; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + void start_tx(); void generate_frame(); void on_tx_progress(const uint32_t progress, const bool done); diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index 2bec78fa..e9018c1c 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -31,6 +31,7 @@ #include "ui_sd_card_debug.hpp" #include "portapack.hpp" +#include "portapack_persistent_memory.hpp" using namespace portapack; #include "irq_controls.hpp" @@ -345,14 +346,17 @@ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) { /* DebugMenuView *********************************************************/ DebugMenuView::DebugMenuView(NavigationView& nav) { + if( portapack::persistent_memory::show_gui_return_icon() ) + { + add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } } } ); + } add_items({ - //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, { "Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav](){ nav.push(); } }, //{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, { "SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav](){ nav.push(); } }, { "Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav](){ nav.push(); } }, { "Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav](){ nav.push(); } }, - { "Buttons test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav](){ nav.push(); } }, + { "Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav](){ nav.push(); } }, }); set_max_rows(2); // allow wider buttons } diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp index 1e3d6003..19118721 100644 --- a/firmware/application/apps/ui_debug.hpp +++ b/firmware/application/apps/ui_debug.hpp @@ -43,6 +43,8 @@ public: void focus() override; + std::string title() const override { return "Memory"; }; + private: Text text_title { { 96, 96, 48, 16 }, @@ -113,6 +115,8 @@ public: void focus() override; + std::string title() const override { return "Temperature"; }; + private: Text text_title { { 76, 16, 240, 16 }, @@ -252,6 +256,8 @@ public: void focus() override; + std::string title() const override { return "Buttons Test"; }; + private: Text text_title { { 64, 16, 184, 16 }, diff --git a/firmware/application/apps/ui_encoders.cpp b/firmware/application/apps/ui_encoders.cpp index e15defd1..05c90a3f 100644 --- a/firmware/application/apps/ui_encoders.cpp +++ b/firmware/application/apps/ui_encoders.cpp @@ -203,6 +203,10 @@ void EncodersView::focus() { } EncodersView::~EncodersView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_ook", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -335,6 +339,15 @@ EncodersView::EncodersView( &tx_view }); + // load app settings + auto rc = settings.load("tx_ook", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + tx_view.on_edit_frequency = [this, &nav]() { auto new_view = nav.push(transmitter_model.tuning_frequency()); new_view->on_changed = [this](rf::Frequency f) { diff --git a/firmware/application/apps/ui_encoders.hpp b/firmware/application/apps/ui_encoders.hpp index ee311e38..ac206f6e 100644 --- a/firmware/application/apps/ui_encoders.hpp +++ b/firmware/application/apps/ui_encoders.hpp @@ -26,6 +26,7 @@ #include "transmitter_model.hpp" #include "encoders.hpp" #include "de_bruijn.hpp" +#include "app_settings.hpp" using namespace encoders; @@ -158,7 +159,7 @@ public: void focus() override; - std::string title() const override { return "OOK transmit"; }; + std::string title() const override { return "OOK TX"; }; private: NavigationView& nav_; @@ -169,6 +170,10 @@ private: SCAN }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + tx_modes tx_mode = IDLE; uint8_t repeat_index { 0 }; uint8_t repeat_min { 0 }; diff --git a/firmware/application/apps/ui_jammer.hpp b/firmware/application/apps/ui_jammer.hpp index 8158a6f7..13869262 100644 --- a/firmware/application/apps/ui_jammer.hpp +++ b/firmware/application/apps/ui_jammer.hpp @@ -106,7 +106,7 @@ public: void focus() override; - std::string title() const override { return "Jammer"; }; + std::string title() const override { return "Jammer TX"; }; private: NavigationView& nav_; diff --git a/firmware/application/apps/ui_keyfob.cpp b/firmware/application/apps/ui_keyfob.cpp index 6492cd6b..b5bfb145 100644 --- a/firmware/application/apps/ui_keyfob.cpp +++ b/firmware/application/apps/ui_keyfob.cpp @@ -136,6 +136,9 @@ void KeyfobView::focus() { } KeyfobView::~KeyfobView() { + // save app settings + settings.save("tx_keyfob", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -214,6 +217,13 @@ KeyfobView::KeyfobView( &tx_view }); + // load app settings + auto rc = settings.load("tx_keyfob", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + frame[0] = 0x55; update_symfields(); diff --git a/firmware/application/apps/ui_keyfob.hpp b/firmware/application/apps/ui_keyfob.hpp index 7f28d554..3cc8419a 100644 --- a/firmware/application/apps/ui_keyfob.hpp +++ b/firmware/application/apps/ui_keyfob.hpp @@ -23,6 +23,7 @@ #include "ui.hpp" #include "ui_transmitter.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" #include "encoders.hpp" using namespace encoders; @@ -36,11 +37,15 @@ public: void focus() override; - std::string title() const override { return "Keyfob (BETA)"; }; + std::string title() const override { return "Key fob TX"; }; private: NavigationView& nav_; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + // 1013210ns / bit static constexpr uint32_t subaru_samples_per_bit = (OOK_SAMPLERATE * 0.00101321); static constexpr uint32_t repeats = 4; diff --git a/firmware/application/apps/ui_lcr.cpp b/firmware/application/apps/ui_lcr.cpp index e664f82e..6f5b1489 100644 --- a/firmware/application/apps/ui_lcr.cpp +++ b/firmware/application/apps/ui_lcr.cpp @@ -39,6 +39,10 @@ void LCRView::focus() { } LCRView::~LCRView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_lcr", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -173,6 +177,15 @@ LCRView::LCRView(NavigationView& nav) { &tx_view }); + // load app settings + auto rc = settings.load("tx_lcr", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + options_scanlist.set_selected_index(0); const auto button_set_am_fn = [this, &nav](Button& button) { diff --git a/firmware/application/apps/ui_lcr.hpp b/firmware/application/apps/ui_lcr.hpp index a9c7548a..bd5b4aac 100644 --- a/firmware/application/apps/ui_lcr.hpp +++ b/firmware/application/apps/ui_lcr.hpp @@ -27,6 +27,7 @@ #include "message.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" namespace ui { @@ -39,7 +40,7 @@ public: void focus() override; - std::string title() const override { return "LCR transmit"; }; + std::string title() const override { return "TEDI/LCR TX"; }; private: struct scan_list_t { @@ -81,6 +82,10 @@ private: SCAN }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + tx_modes tx_mode = IDLE; uint8_t scan_count { 0 }, scan_index { 0 }; uint32_t scan_progress { 0 }; diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index bda0f278..68d98212 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -186,7 +186,7 @@ void MicTXView::rxaudio(bool is_on) { baseband::run_image(portapack::spi_flash::image_tag_mic_tx); audio::output::stop(); - audio::input::start(ak4951_alc_GUI_selected); // set up audio input = mic config of any audio coded AK4951/WM8731, (in WM8731 parameter will be ignored) + audio::input::start(); // set up audio input = mic config of any audio coded AK4951/WM8731, (in WM8731 parameter will be ignored) portapack::pin_i2s0_rx_sda.mode(3); configure_baseband(); } @@ -212,7 +212,7 @@ MicTXView::MicTXView( baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - if ( audio_codec_wm8731.detected() ) { + if (true ) { // Temporary , disabling ALC feature , (pending to solve -No Audio in Mic app ,in some H2/H2+ WM /QFP100 CPLS users- if ( audio_codec_wm8731.detected() ) { add_children({ &labels_WM8731, // we have audio codec WM8731, same MIC menu as original. &vumeter, @@ -285,7 +285,7 @@ MicTXView::MicTXView( options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { ak4951_alc_GUI_selected = v; - audio::input::start(ak4951_alc_GUI_selected); + audio::input::start(); }; // options_ak4951_alc_mode.set_selected_index(0); @@ -341,23 +341,37 @@ MicTXView::MicTXView( enable_dsb = false; field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); //if (rx_enabled) - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + options_tone_key.hidden(0); // we are in FM mode , we should have active the Key-tones & CTCSS option. + field_rxbw.hidden(0); // we are in FM mode, we need to allow the user set up of the RX NFM BW selection (8K5, 11K, 16K) break; case 1: enable_am = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + options_tone_key.set_selected_index(0); // we are NOT in FM mode , we reset the possible previous key-tones &CTCSS selection. + set_dirty(); // Refresh display + options_tone_key.hidden(1); // we hide that Key-tones & CTCSS input selecction, (no meaning in AM/DSB/SSB). + field_rxbw.hidden(1); // we hide the NFM BW selection in other modes non_FM (no meaning in AM/DSB/SSB) + check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. break; case 2: enable_usb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. + check_rogerbeep.hidden(1); // hide that roger beep selection. + set_dirty(); // Refresh display break; case 3: enable_lsb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. + check_rogerbeep.hidden(1); // hide that roger beep selection. + set_dirty(); // Refresh display break; case 4: enable_dsb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. break; } //configure_baseband(); @@ -525,7 +539,7 @@ MicTXView::MicTXView( set_tx(false); audio::set_rate(audio::Rate::Hz_24000); - audio::input::start(ak4951_alc_GUI_selected); // originally , audio::input::start(); (we added parameter) + audio::input::start(); // originally , audio::input::start(); (we added parameter) } MicTXView::~MicTXView() { diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index aaab059c..9b091e53 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -58,7 +58,7 @@ public: }; */ - std::string title() const override { return "Mic TX RX"; }; + std::string title() const override { return "Microphone"; }; private: static constexpr uint32_t sampling_rate = 1536000U; diff --git a/firmware/application/apps/ui_morse.cpp b/firmware/application/apps/ui_morse.cpp index ebe44b6d..1c9468d9 100644 --- a/firmware/application/apps/ui_morse.cpp +++ b/firmware/application/apps/ui_morse.cpp @@ -97,6 +97,10 @@ void MorseView::focus() { } MorseView::~MorseView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_morse", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -203,6 +207,15 @@ MorseView::MorseView( &tx_view }); + // load app settings + auto rc = settings.load("tx_morse", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + // Default settings field_speed.set_value(15); // 15wps field_tone.set_value(700); // 700Hz FM tone diff --git a/firmware/application/apps/ui_morse.hpp b/firmware/application/apps/ui_morse.hpp index 5079fea8..90b60b49 100644 --- a/firmware/application/apps/ui_morse.hpp +++ b/firmware/application/apps/ui_morse.hpp @@ -27,7 +27,7 @@ #include "ui_widget.hpp" #include "ui_navigation.hpp" #include "ui_transmitter.hpp" - +#include "app_settings.hpp" #include "portapack.hpp" #include "message.hpp" #include "volume.hpp" @@ -67,6 +67,10 @@ private: std::string message { }; uint32_t time_units { 0 }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + enum modulation_t { CW = 0, FM = 1 diff --git a/firmware/application/apps/ui_nrf_rx.cpp b/firmware/application/apps/ui_nrf_rx.cpp index 32982ae6..d5d916f8 100644 --- a/firmware/application/apps/ui_nrf_rx.cpp +++ b/firmware/application/apps/ui_nrf_rx.cpp @@ -60,6 +60,14 @@ NRFRxView::NRFRxView(NavigationView& nav) { &console }); + // load app settings + auto rc = settings.load("rx_nrf", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + } + // DEBUG record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); @@ -157,6 +165,11 @@ void NRFRxView::on_data(uint32_t value, bool is_data) { } NRFRxView::~NRFRxView() { + + // save app settings + app_settings.rx_frequency = field_frequency.value(); + settings.save("rx_nrf", &app_settings); + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/ui_nrf_rx.hpp b/firmware/application/apps/ui_nrf_rx.hpp index 4f72b25b..18a6f814 100644 --- a/firmware/application/apps/ui_nrf_rx.hpp +++ b/firmware/application/apps/ui_nrf_rx.hpp @@ -27,6 +27,7 @@ #include "ui.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" +#include "app_settings.hpp" #include "ui_record_view.hpp" // DEBUG #include "utility.hpp" @@ -45,6 +46,10 @@ public: private: void on_data(uint32_t value, bool is_data); + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + uint8_t console_color { 0 }; uint32_t prev_value { 0 }; std::string str_log { "" }; diff --git a/firmware/application/apps/ui_pocsag_tx.cpp b/firmware/application/apps/ui_pocsag_tx.cpp index 56ced719..58de068e 100644 --- a/firmware/application/apps/ui_pocsag_tx.cpp +++ b/firmware/application/apps/ui_pocsag_tx.cpp @@ -38,6 +38,10 @@ void POCSAGTXView::focus() { } POCSAGTXView::~POCSAGTXView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_pocsag", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -141,6 +145,15 @@ POCSAGTXView::POCSAGTXView( &tx_view }); + // load app settings + auto rc = settings.load("tx_pocsag", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + options_bitrate.set_selected_index(1); // 1200bps options_type.set_selected_index(0); // Address only diff --git a/firmware/application/apps/ui_pocsag_tx.hpp b/firmware/application/apps/ui_pocsag_tx.hpp index 0dfbc30a..470ce0fe 100644 --- a/firmware/application/apps/ui_pocsag_tx.hpp +++ b/firmware/application/apps/ui_pocsag_tx.hpp @@ -31,6 +31,7 @@ #include "bch_code.hpp" #include "message.hpp" #include "transmitter_model.hpp" +#include "app_settings.hpp" #include "pocsag.hpp" using namespace pocsag; @@ -62,6 +63,10 @@ private: 5, 31, 21, 2 }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + void on_set_text(NavigationView& nav); void on_tx_progress(const uint32_t progress, const bool done); bool start_tx(); diff --git a/firmware/application/apps/ui_rds.cpp b/firmware/application/apps/ui_rds.cpp index db9e2d2a..7e8f1da8 100644 --- a/firmware/application/apps/ui_rds.cpp +++ b/firmware/application/apps/ui_rds.cpp @@ -175,6 +175,10 @@ void RDSView::focus() { } RDSView::~RDSView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_rds", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -226,11 +230,17 @@ RDSView::RDSView( &view_radiotext, &view_datetime, &view_audio, - //&options_countrycode, - //&options_coverage, &tx_view, }); - + + // load app settings + auto rc = settings.load("tx_rds", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } check_TP.set_value(true); sym_pi_code.set_sym(0, 0xF); @@ -242,8 +252,6 @@ RDSView::RDSView( }; options_pty.set_selected_index(0); // None - //options_countrycode.set_selected_index(18); // Baguette du fromage - //options_coverage.set_selected_index(0); // Local tx_view.on_edit_frequency = [this, &nav]() { auto new_view = nav.push(receiver_model.tuning_frequency()); diff --git a/firmware/application/apps/ui_rds.hpp b/firmware/application/apps/ui_rds.hpp index 6e6e0797..bbffb1ed 100644 --- a/firmware/application/apps/ui_rds.hpp +++ b/firmware/application/apps/ui_rds.hpp @@ -24,7 +24,7 @@ #include "ui_transmitter.hpp" #include "ui_textentry.hpp" #include "ui_tabview.hpp" - +#include "app_settings.hpp" #include "rds.hpp" using namespace rds; @@ -144,12 +144,17 @@ public: void focus() override; - std::string title() const override { return "RDS transmit"; }; + std::string title() const override { return "RDS TX"; }; private: NavigationView& nav_; RDS_flags rds_flags { }; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + + std::vector frame_psn { }; std::vector frame_radiotext { }; std::vector frame_datetime { }; diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 3bd350c8..29cdb10d 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -540,7 +540,7 @@ size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thre field_bw.set_selected_index(0); receiver_model.set_am_configuration(field_bw.selected_index()); field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n); }; - receiver_model.set_sampling_rate(2000000);receiver_model.set_baseband_bandwidth(2000000); + receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); break; case WFM: bw.emplace_back("16k", 0); diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp index 3936904e..caa571f9 100644 --- a/firmware/application/apps/ui_scanner.hpp +++ b/firmware/application/apps/ui_scanner.hpp @@ -111,7 +111,7 @@ public: .foreground = Color::red(), }; - std::string title() const override { return "SCANNER"; }; + std::string title() const override { return "Scanner"; }; std::vector frequency_list{ }; std::vector description_list { }; diff --git a/firmware/application/apps/ui_sd_wipe.hpp b/firmware/application/apps/ui_sd_wipe.hpp index 6d49b6f4..fc593f16 100644 --- a/firmware/application/apps/ui_sd_wipe.hpp +++ b/firmware/application/apps/ui_sd_wipe.hpp @@ -38,7 +38,7 @@ public: ~WipeSDView(); void focus() override; - std::string title() const override { return "Wipe FAT"; }; + std::string title() const override { return "Wipe SD Card"; }; private: NavigationView& nav_; diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index a928ea43..93786c38 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -234,6 +234,7 @@ SetUIView::SetUIView(NavigationView& nav) { &checkbox_showsplash, &checkbox_showclock, &options_clockformat, + &checkbox_guireturnflag, &button_save, &button_cancel }); @@ -242,14 +243,11 @@ SetUIView::SetUIView(NavigationView& nav) { checkbox_speaker.set_value(persistent_memory::config_speaker()); checkbox_showsplash.set_value(persistent_memory::config_splash()); checkbox_showclock.set_value(!persistent_memory::hide_clock()); + checkbox_guireturnflag.set_value(persistent_memory::show_gui_return_icon()); - uint32_t backlight_timer = persistent_memory::config_backlight_timer(); - if (backlight_timer) { - checkbox_bloff.set_value(true); - options_bloff.set_by_value(backlight_timer); - } else { - options_bloff.set_selected_index(0); - } + const auto backlight_config = persistent_memory::config_backlight_timer(); + checkbox_bloff.set_value(backlight_config.timeout_enabled()); + options_bloff.set_by_value(backlight_config.timeout_enum()); if (persistent_memory::clock_with_date()) { options_clockformat.set_selected_index(1); @@ -257,19 +255,13 @@ SetUIView::SetUIView(NavigationView& nav) { options_clockformat.set_selected_index(0); } - //checkbox_speaker.on_select = [this](Checkbox&, bool v) { - // if (v) audio::output::speaker_mute(); //Just mute audio if speaker is disabled - // persistent_memory::set_config_speaker(v); //Store Speaker status - // StatusRefreshMessage message { }; //Refresh status bar with/out speaker - // EventDispatcher::send_message(message); - //}; button_save.on_select = [&nav, this](Button&) { - if (checkbox_bloff.value()) - persistent_memory::set_config_backlight_timer(options_bloff.selected_index() + 1); - else - persistent_memory::set_config_backlight_timer(0); - + persistent_memory::set_config_backlight_timer({ + (persistent_memory::backlight_timeout_t)options_bloff.selected_index_value(), + checkbox_bloff.value() + }); + if (checkbox_showclock.value()){ if (options_clockformat.selected_index() == 1) persistent_memory::set_clock_with_date(true); @@ -284,6 +276,7 @@ SetUIView::SetUIView(NavigationView& nav) { persistent_memory::set_config_splash(checkbox_showsplash.value()); persistent_memory::set_clock_hidden(!checkbox_showclock.value()); + persistent_memory::set_gui_return_icon(checkbox_guireturnflag.value()); persistent_memory::set_disable_touchscreen(checkbox_disable_touchscreen.value()); nav.pop(); }; @@ -296,6 +289,36 @@ void SetUIView::focus() { button_save.focus(); } + +// --------------------------------------------------------- +// Appl. Settings +// --------------------------------------------------------- +SetAppSettingsView::SetAppSettingsView(NavigationView& nav) { + add_children({ + &checkbox_load_app_settings, + &checkbox_save_app_settings, + &button_save, + &button_cancel + }); + + checkbox_load_app_settings.set_value(persistent_memory::load_app_settings()); + checkbox_save_app_settings.set_value(persistent_memory::save_app_settings()); + + + button_save.on_select = [&nav, this](Button&) { + persistent_memory::set_load_app_settings(checkbox_load_app_settings.value()); + persistent_memory::set_save_app_settings(checkbox_save_app_settings.value()); + nav.pop(); + }; + button_cancel.on_select = [&nav, this](Button&) { + nav.pop(); + }; +} + +void SetAppSettingsView::focus() { + button_save.focus(); +} + SetAudioView::SetAudioView(NavigationView& nav) { add_children({ &labels, @@ -344,14 +367,22 @@ void SetQRCodeView::focus() { button_save.focus(); } +// --------------------------------------------------------- +// Settings main menu +// --------------------------------------------------------- SettingsMenuView::SettingsMenuView(NavigationView& nav) { + if( portapack::persistent_memory::show_gui_return_icon() ) + { + add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } } } ); + } add_items({ { "Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav](){ nav.push(); } }, { "Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav](){ nav.push(); } }, - { "Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav](){ nav.push(); } }, + { "User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav](){ nav.push(); } }, { "Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav](){ nav.push(); } }, - { "Touchscreen", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav](){ nav.push(); } }, - { "QR code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav](){ nav.push(); } } + { "Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav](){ nav.push(); } }, + { "App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, + { "QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav](){ nav.push(); } } }); set_max_rows(2); // allow wider buttons } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 03bb4e8c..cbffdaae 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -27,6 +27,7 @@ #include "ui_menu.hpp" #include "ui_navigation.hpp" #include "ff.h" +#include "portapack_persistent_memory.hpp" #include @@ -47,7 +48,7 @@ public: void focus() override; - std::string title() const override { return "Set Date/Time"; }; + std::string title() const override { return "Date/Time"; }; private: Labels labels { @@ -210,6 +211,8 @@ private: SetFrequencyCorrectionModel form_collect(); }; +using portapack::persistent_memory::backlight_timeout_t; + class SetUIView : public View { public: SetUIView(NavigationView& nav); @@ -241,13 +244,14 @@ private: { 52, 7 * 16 + 8 }, 20, { - { "5 seconds", 5 }, - { "15 seconds", 15 }, - { "30 seconds", 30 }, - { "1 minute", 60 }, - { "3 minutes", 180 }, - { "5 minutes", 300 }, - { "10 minutes", 600 } + { "5 seconds", backlight_timeout_t::Timeout5Sec }, + { "15 seconds", backlight_timeout_t::Timeout15Sec }, + { "30 seconds", backlight_timeout_t::Timeout30Sec }, + { "1 minute", backlight_timeout_t::Timeout60Sec }, + { "3 minutes", backlight_timeout_t::Timeout180Sec }, + { "5 minutes", backlight_timeout_t::Timeout300Sec }, + { "10 minutes", backlight_timeout_t::Timeout600Sec }, + { "1 hour", backlight_timeout_t::Timeout3600Sec }, } }; @@ -271,6 +275,45 @@ private: { "time and date", 1 } } }; + + Checkbox checkbox_guireturnflag { + { 3 * 8, 14 * 16 }, + 25, + "add return icon in GUI" + }; + + Button button_save { + { 2 * 8, 16 * 16, 12 * 8, 32 }, + "Save" + }; + + Button button_cancel { + { 16 * 8, 16 * 16, 12 * 8, 32 }, + "Cancel", + }; +}; + +class SetAppSettingsView : public View { +public: + SetAppSettingsView(NavigationView& nav); + + void focus() override; + + std::string title() const override { return "App Settings"; }; + +private: + + Checkbox checkbox_load_app_settings { + { 3 * 8, 2 * 16 }, + 25, + "Load app settings" + }; + + Checkbox checkbox_save_app_settings { + { 3 * 8, 4 * 16 }, + 25, + "Save app settings" + }; Button button_save { { 2 * 8, 16 * 16, 12 * 8, 32 }, @@ -322,7 +365,7 @@ public: void focus() override; - std::string title() const override { return "QR code"; }; + std::string title() const override { return "QR Code"; }; private: Checkbox checkbox_bigger_qr { diff --git a/firmware/application/apps/ui_siggen.hpp b/firmware/application/apps/ui_siggen.hpp index 5abcdd85..f55d19d1 100644 --- a/firmware/application/apps/ui_siggen.hpp +++ b/firmware/application/apps/ui_siggen.hpp @@ -40,7 +40,7 @@ public: void focus() override; - std::string title() const override { return "Generator"; }; + std::string title() const override { return "Signal gen"; }; private: void start_tx(); diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index f38fc3dd..5ddf157e 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -23,6 +23,7 @@ #include "ui_sonde.hpp" #include "baseband_api.hpp" #include "audio.hpp" +#include "app_settings.hpp" #include "portapack.hpp" #include @@ -43,6 +44,8 @@ namespace ui { SondeView::SondeView(NavigationView& nav) { + + baseband::run_image(portapack::spi_flash::image_tag_sonde); add_children({ @@ -68,8 +71,17 @@ SondeView::SondeView(NavigationView& nav) { &button_see_map }); - // start from the frequency currently stored in the receiver_model: - target_frequency_ = receiver_model.tuning_frequency(); + + // load app settings + auto rc = settings.load("rx_sonde", &app_settings); + if(rc == SETTINGS_OK) { + field_lna.set_value(app_settings.lna); + field_vga.set_value(app_settings.vga); + field_rf_amp.set_value(app_settings.rx_amp); + target_frequency_ = app_settings.rx_frequency; + } + else target_frequency_ = receiver_model.tuning_frequency(); + field_frequency.set_value(target_frequency_); field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning @@ -104,16 +116,6 @@ SondeView::SondeView(NavigationView& nav) { receiver_model.set_sampling_rate(sampling_rate); receiver_model.set_baseband_bandwidth(baseband_bandwidth); receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias. - - /* radio::enable({ // this can be removed, previous version, no DC-bias ant. control. - tuning_frequency(), - sampling_rate, - baseband_bandwidth, - rf::Direction::Receive, - receiver_model.rf_amp(), - static_cast(receiver_model.lna()), - static_cast(receiver_model.vga()), - }); */ // QR code with geo URI @@ -157,9 +159,13 @@ SondeView::SondeView(NavigationView& nav) { } SondeView::~SondeView() { + // save app settings + app_settings.rx_frequency = target_frequency_; + settings.save("rx_sonde", &app_settings); + baseband::set_pitch_rssi(0, false); -/* radio::disable(); */ - receiver_model.disable(); // to switch off all, including DC bias. + + receiver_model.disable(); // to switch off all, including DC bias. baseband::shutdown(); audio::output::stop(); } diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index b1fab391..3129c72b 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -34,7 +34,7 @@ #include "log_file.hpp" #include "sonde_packet.hpp" - +#include "app_settings.hpp" #include #include @@ -74,6 +74,9 @@ private: bool beep { false }; char geo_uri[32] = {}; + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; sonde::GPS_data gps_info { }; sonde::temp_humid temp_humid_info { }; diff --git a/firmware/application/apps/ui_sstvtx.cpp b/firmware/application/apps/ui_sstvtx.cpp index 4943315d..55e882d2 100644 --- a/firmware/application/apps/ui_sstvtx.cpp +++ b/firmware/application/apps/ui_sstvtx.cpp @@ -88,6 +88,10 @@ void SSTVTXView::paint(Painter&) { } SSTVTXView::~SSTVTXView() { + // save app settings + app_settings.tx_frequency = transmitter_model.tuning_frequency(); + settings.save("tx_sstv", &app_settings); + transmitter_model.disable(); baseband::shutdown(); } @@ -215,6 +219,15 @@ SSTVTXView::SSTVTXView( options_t mode_options; uint32_t c; + // load app settings + auto rc = settings.load("tx_sstv", &app_settings); + if(rc == SETTINGS_OK) { + transmitter_model.set_rf_amp(app_settings.tx_amp); + transmitter_model.set_channel_bandwidth(app_settings.channel_bandwidth); + transmitter_model.set_tuning_frequency(app_settings.tx_frequency); + transmitter_model.set_tx_gain(app_settings.tx_gain); + } + // Search for valid bitmaps file_list = scan_root_files(u"/sstv", u"*.bmp"); if (!file_list.size()) { diff --git a/firmware/application/apps/ui_sstvtx.hpp b/firmware/application/apps/ui_sstvtx.hpp index 8c320680..97f2cd68 100644 --- a/firmware/application/apps/ui_sstvtx.hpp +++ b/firmware/application/apps/ui_sstvtx.hpp @@ -34,6 +34,7 @@ #include "sstv.hpp" #include "file.hpp" #include "bmp.hpp" +#include "app_settings.hpp" using namespace sstv; @@ -58,7 +59,10 @@ private: NavigationView& nav_; sstv_scanline scanline_buffer { }; - + // app save settings + std::app_settings settings { }; + std::app_settings::AppSettings app_settings { }; + bool file_error { false }; File bmp_file { }; bmp_header_t bmp_header { }; diff --git a/firmware/application/apps/ui_touch_calibration.cpp b/firmware/application/apps/ui_touch_calibration.cpp index a5a7c348..26960106 100644 --- a/firmware/application/apps/ui_touch_calibration.cpp +++ b/firmware/application/apps/ui_touch_calibration.cpp @@ -31,7 +31,7 @@ namespace ui { TouchCalibrationView::TouchCalibrationView( NavigationView& nav ) : nav { nav }, - calibration { touch::default_calibration() } + calibration { touch::Calibration() } { add_children({ &image_calibrate_0, diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp index ce32076c..4ba23acc 100644 --- a/firmware/application/audio.cpp +++ b/firmware/application/audio.cpp @@ -168,8 +168,8 @@ void speaker_mute() { namespace input { -void start(int8_t alc_mode) { - audio_codec->microphone_enable(alc_mode); // added user-GUI selection for AK4951, ALC mode parameter. +void start() { + audio_codec->microphone_enable(); i2s::i2s0::rx_start(); } diff --git a/firmware/application/audio.hpp b/firmware/application/audio.hpp index 56301ee8..b02e42aa 100644 --- a/firmware/application/audio.hpp +++ b/firmware/application/audio.hpp @@ -49,7 +49,7 @@ public: virtual volume_range_t headphone_gain_range() const = 0; virtual void set_headphone_volume(const volume_t volume) = 0; - virtual void microphone_enable(int8_t alc_mode) = 0; // added user-GUI AK4951 ,selected ALC mode. + virtual void microphone_enable() = 0; virtual void microphone_disable() = 0; virtual size_t reg_count() const = 0; @@ -59,7 +59,7 @@ public: namespace output { -void start(); // this other start(),no changed. ,in namespace output , used to config audio playback mode, +void start(); void stop(); void mute(); @@ -72,7 +72,7 @@ void speaker_unmute(); namespace input { -void start(int8_t alc_mode); // added parameter user-GUI select AK4951-ALC mode for config mic path,(recording mode in datasheet), +void start(); void stop(); } /* namespace input */ diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index 8c11b2fa..d15df9fe 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -226,15 +226,17 @@ void EventDispatcher::handle_rtc_tick() { portapack::temperature_logger.second_tick(); - uint32_t backlight_timer = portapack::persistent_memory::config_backlight_timer(); - if (backlight_timer) { - if (portapack::bl_tick_counter == backlight_timer) + const auto backlight_timer = portapack::persistent_memory::config_backlight_timer(); + if (backlight_timer.timeout_enabled()) { + if (portapack::bl_tick_counter == backlight_timer.timeout_seconds()) set_display_sleep(true); else portapack::bl_tick_counter++; } rtc_time::on_tick_second(); + + portapack::persistent_memory::cache::persist(); } ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent event) { diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 0157cd4f..99a47d0b 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -215,7 +215,7 @@ static int load_config(){ static Optional config_value; if(!config_value.is_valid()){ int8_t value = portapack::persistent_memory::config_cpld(); - if((value <= 0 || value >= 4) && sd_card::status() == sd_card::Status::Mounted){ + if((value <= 0 || value >= 5) && sd_card::status() == sd_card::Status::Mounted){ int data = read_file("/hardware/settings.txt"); if(data != -1) { config_value = data; @@ -235,14 +235,19 @@ static PortaPackModel portapack_model() { const auto switches_state = get_switches_state(); if (switches_state[(size_t)ui::KeyEvent::Up]){ save_config(1); - model = PortaPackModel::R2_20170522; + // model = PortaPackModel::R2_20170522; // Commented these out as they should be set down below anyway } else if (switches_state[(size_t)ui::KeyEvent::Down]){ save_config(2); - model = PortaPackModel::R1_20150901; + // model = PortaPackModel::R1_20150901; } else if (switches_state[(size_t)ui::KeyEvent::Left]){ save_config(3); + // model = PortaPackModel::R1_20150901; + } + else if (switches_state[(size_t)ui::KeyEvent::Right]){ + save_config(4); + // model = PortaPackModel::R2_20170522; } else if (switches_state[(size_t)ui::KeyEvent::Select]){ save_config(0); @@ -253,6 +258,10 @@ static PortaPackModel portapack_model() { model = PortaPackModel::R2_20170522; } else if (load_config() == 2) { model = PortaPackModel::R1_20150901; + } else if (load_config() == 3) { + model = PortaPackModel::R1_20150901; + } else if (load_config() == 4) { + model = PortaPackModel::R2_20170522; } else { if( audio_codec_wm8731.detected() ) { model = PortaPackModel::R1_20150901; // H1R1 @@ -403,6 +412,7 @@ bool init() { // if( !hackrf::cpld::load_sram() ) { // chSysHalt(); // } + chThdSleepMilliseconds(100); configure_pins_portapack(); @@ -412,6 +422,8 @@ bool init() { i2c0.stop(); + chThdSleepMilliseconds(10); + set_clock_config(clock_config_irc); cgu::pll1::disable(); @@ -452,9 +464,14 @@ bool init() { cgu::pll1::direct(); i2c0.start(i2c_config_fast_clock); + chThdSleepMilliseconds(10); + + /* Cache some configuration data from persistent memory. */ + persistent_memory::cache::init(); touch::adc::init(); controls_init(); + chThdSleepMilliseconds(10); clock_manager.set_reference_ppb(persistent_memory::correction_ppb()); clock_manager.enable_first_if_clock(); @@ -465,12 +482,12 @@ bool init() { sdcStart(&SDCD1, nullptr); sd_card::poll_inserted(); - chThdSleepMilliseconds(1); + chThdSleepMilliseconds(10); if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) { - chThdSleepMilliseconds(1); + chThdSleepMilliseconds(10); // If using a "2021/12 QFP100", press and hold the left button while booting. Should only need to do once. - if (load_config() != 3){ + if (load_config() != 3 && load_config() != 4){ shutdown_base(); return false; } @@ -480,11 +497,13 @@ bool init() { chSysHalt(); } - chThdSleepMilliseconds(1); // This delay seems to solve white noise audio issues + chThdSleepMilliseconds(10); // This delay seems to solve white noise audio issues LPC_CREG->DMAMUX = portapack::gpdma_mux; gpdma::controller.enable(); + chThdSleepMilliseconds(10); + audio::init(portapack_audio_codec()); diff --git a/firmware/application/serializer.hpp b/firmware/application/serializer.hpp index 3aedfb24..124dd69e 100644 --- a/firmware/application/serializer.hpp +++ b/firmware/application/serializer.hpp @@ -45,6 +45,14 @@ struct serial_format_t { parity_enum parity; uint8_t stop_bits; order_enum bit_order; + + constexpr serial_format_t() : + data_bits(7), + parity(parity_enum::EVEN), + stop_bits(1), + bit_order(order_enum::LSB_FIRST) + { + } }; size_t symbol_count(const serial_format_t& serial_format); diff --git a/firmware/application/touch.cpp b/firmware/application/touch.cpp index 63c7bb47..681c2518 100644 --- a/firmware/application/touch.cpp +++ b/firmware/application/touch.cpp @@ -76,14 +76,6 @@ ui::Point Calibration::translate(const DigitizerPoint& p) const { return { x_clipped, y_clipped }; } -const Calibration default_calibration() { - /* Values derived from one PortaPack H1 unit. */ - return { - { { { 256, 731 }, { 880, 432 }, { 568, 146 } } }, - { { { 32, 48 }, { 208, 168 }, { 120, 288 } } } - }; -}; - void Manager::feed(const Frame& frame) { // touch_debounce.feed(touch_raw); const auto touch_raw = frame.touch; diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index ebea3c92..7fa1c029 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -137,6 +137,15 @@ struct Calibration { { } + constexpr Calibration() : + Calibration( + /* Values derived from one PortaPack H1 unit. */ + { { { 256, 731 }, { 880, 432 }, { 568, 146 } } }, + { { { 32, 48 }, { 208, 168 }, { 120, 288 } } } + ) + { + } + ui::Point translate(const DigitizerPoint& p) const; private: @@ -149,8 +158,6 @@ private: int32_t f; }; -const Calibration default_calibration(); - template class Filter { public: diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 435a7b73..9d310a62 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -464,8 +464,11 @@ void NavigationView::focus() { /* ReceiversMenuView *****************************************************/ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { - add_items({ - //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, + if( portapack::persistent_memory::show_gui_return_icon() ) + { + add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } ); + } + add_items( { { "ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, //{ "ACARS", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); }, }, { "AIS Boats", ui::Color::green(), &bitmap_icon_ais, [&nav](){ nav.push(); } }, @@ -485,16 +488,19 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) { { "LoRa", ui::Color::dark_grey(), &bitmap_icon_lora, [&nav](){ nav.push(); } }, { "SSTV", ui::Color::dark_grey(), &bitmap_icon_sstv, [&nav](){ nav.push(); } }, { "TETRA", ui::Color::dark_grey(), &bitmap_icon_tetra, [&nav](){ nav.push(); } },*/ - }); - - //set_highlighted(4); // Default selection is "Audio" + } ); + + //set_highlighted(0); // Default selection is "Audio" } /* TransmittersMenuView **************************************************/ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { - add_items({ - //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, + if( portapack::persistent_memory::show_gui_return_icon() ) + { + add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } ); + } + add_items({ { "ADS-B [S]", ui::Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push(); } }, { "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push(); } }, { "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push(); } }, @@ -519,17 +525,20 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) { /* UtilitiesMenuView *****************************************************/ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) { + if( portapack::persistent_memory::show_gui_return_icon() ) + { + add_items( { { "..", ui::Color::light_grey(),&bitmap_icon_previous , [&nav](){ nav.pop(); } } } ); + } add_items({ //{ "Test app", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push(); } }, - //{ "..", ui::Color::light_grey(),&bitmap_icon_previous, [&nav](){ nav.pop(); } }, - { "Freq manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, + { "Freq. manager", ui::Color::green(), &bitmap_icon_freqman, [&nav](){ nav.push(); } }, { "File manager", ui::Color::yellow(), &bitmap_icon_dir, [&nav](){ nav.push(); } }, //{ "Notepad", ui::Color::dark_grey(), &bitmap_icon_notepad, [&nav](){ nav.push(); } }, { "Signal gen", ui::Color::green(), &bitmap_icon_cwgen, [&nav](){ nav.push(); } }, //{ "Tone search", ui::Color::dark_grey(), nullptr, [&nav](){ nav.push(); } }, - { "Wave viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, + { "WAV viewer", ui::Color::yellow(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, { "Antenna length", ui::Color::green(), &bitmap_icon_tools_antenna, [&nav](){ nav.push(); } }, - { "Wipe SD card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push(); } }, + { "Wipe SD Card", ui::Color::red(), &bitmap_icon_tools_wipesd, [&nav](){ nav.push(); } }, }); set_max_rows(2); // allow wider buttons } @@ -553,12 +562,12 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "Transmit", ui::Color::cyan(), &bitmap_icon_transmit, [&nav](){ nav.push(); } }, { "Capture", ui::Color::red(), &bitmap_icon_capture, [&nav](){ nav.push(); } }, { "Replay", ui::Color::green(), &bitmap_icon_replay, [&nav](){ nav.push(); } }, - { "Calls", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push(); } }, + { "Search", ui::Color::yellow(), &bitmap_icon_search, [&nav](){ nav.push(); } }, { "Scanner", ui::Color::yellow(), &bitmap_icon_scanner, [&nav](){ nav.push(); } }, { "Microphone", ui::Color::yellow(), &bitmap_icon_microphone,[&nav](){ nav.push(); } }, { "Looking Glass", ui::Color::yellow(), &bitmap_icon_looking, [&nav](){ nav.push(); } }, - { "Tools", ui::Color::cyan(), &bitmap_icon_utilities, [&nav](){ nav.push(); } }, - { "Options", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, + { "Utilities", ui::Color::cyan(), &bitmap_icon_utilities, [&nav](){ nav.push(); } }, + { "Settings", ui::Color::cyan(), &bitmap_icon_setup, [&nav](){ nav.push(); } }, { "Debug", ui::Color::light_grey(), &bitmap_icon_debug, [&nav](){ nav.push(); } }, { "HackRF", ui::Color::cyan(), &bitmap_icon_hackrf, [this, &nav](){ hackrf_mode(nav); } }, //{ "About", ui::Color::cyan(), nullptr, [&nav](){ nav.push(); } } diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 68723744..d0e3b03f 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -248,14 +248,14 @@ namespace ui { public: ReceiversMenuView(NavigationView &nav); - std::string title() const override { return "Receivers"; }; + std::string title() const override { return "Receive"; }; }; class TransmittersMenuView : public BtnGridView { public: TransmittersMenuView(NavigationView &nav); - std::string title() const override { return "Transmitters"; }; + std::string title() const override { return "Transmit"; }; }; class UtilitiesMenuView : public BtnGridView diff --git a/firmware/application/ui_sd_card_debug.hpp b/firmware/application/ui_sd_card_debug.hpp index 170c2a68..56253c53 100644 --- a/firmware/application/ui_sd_card_debug.hpp +++ b/firmware/application/ui_sd_card_debug.hpp @@ -38,6 +38,8 @@ public: void focus() override; + std::string title() const override { return "SD Card"; }; + private: SignalToken sd_card_status_signal_token { }; diff --git a/firmware/baseband/dsp_modulate.cpp b/firmware/baseband/dsp_modulate.cpp index 31dd3f85..04102800 100644 --- a/firmware/baseband/dsp_modulate.cpp +++ b/firmware/baseband/dsp_modulate.cpp @@ -21,6 +21,8 @@ #include "dsp_modulate.hpp" #include "sine_table_int8.hpp" +#include "portapack_shared_memory.hpp" +#include "tonesets.hpp" namespace dsp { namespace modulate { @@ -40,13 +42,42 @@ void Modulator::set_over(uint32_t new_over) { over = new_over; } +void Modulator::set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep ) { + audio_gain = new_audio_gain ; + play_beep = new_play_beep; + +} + +int32_t Modulator::apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message ) { + + if (play_beep) { // We need to add audio beep sample. + if (new_beep_timer) { + new_beep_timer--; + } else { + new_beep_timer = baseband_fs * 0.05; // 50ms + + if (new_beep_index == BEEP_TONES_NB) { + configured_in = false; + shared_memory.application_queue.push(new_txprogress_message); + } else { + beep_gen.configure(beep_deltas[new_beep_index], 1.0); // config sequentially the audio beep tone. + new_beep_index++; + } + } + sample_in = beep_gen.process(0); // Get sample of the selected sequence of 6 beep tones , and overwrite audio sample. Mix 0%. + } + return sample_in; // Return audio mic scaled with gain , 8 bit sample or audio beep sample. +} + + /// SSB::SSB() : hilbert() { mode = Mode::LSB; } -void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer,TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { + // No way to activate correctly the roger beep in this option, Maybe not enough M4 CPU power , Let's block roger beep in SSB selection by now . int32_t sample = 0; int8_t re = 0, im = 0; @@ -55,7 +86,9 @@ void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { float i = 0.0, q = 0.0; sample = audio.p[counter / over] >> 2; - //switch (mode) { + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. + + //switch (mode) { //case Mode::LSB: hilbert.execute(sample / 32768.0f, i, q); //case Mode::USB: hilbert.execute(sample / 32768.0f, q, i); @@ -72,9 +105,23 @@ void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { //re = q; //im = i; //break; + } buffer.p[counter] = { re, im }; + + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider *8); // Why ? . This division is to adj vu-meter sentitivity, to match saturation point to red-muter . + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + } } @@ -88,15 +135,39 @@ void FM::set_fm_delta(uint32_t new_delta) { fm_delta = new_delta; } -void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void FM::set_tone_gen_configure(const uint32_t set_delta, const float set_tone_mix_weight) { + tone_gen.configure(set_delta, set_tone_mix_weight); +} + +void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { int32_t sample = 0; int8_t re, im; for (size_t counter = 0; counter < buffer.count; counter++) { - if (counter % over == 0) { - sample = audio.p[counter / over] >> 8; - delta = sample * fm_delta; - } + + sample = audio.p[counter>>6] >> 8; // sample = audio.p[counter / over] >> 8; (not enough efficient running code, over = 1536000/240000= 64 ) + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. + + if (play_beep) { + sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message ); // Apply beep -if selected - atom ,sample by sample. + } else { + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider / 4); // Why ? . This division is to adj vu-meter sentitivity, to match saturation point to red-muter . + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + // TODO: pending to optimize CPU running code. + // So far , we can not handle all 3 issues at the same time (vu-meter , CTCSS, beep). + sample = tone_gen.process(sample); // Add selected Key_Tone or CTCSS subtone , atom function() , sample by sample. + } + + delta = sample * fm_delta; // Modulate FM phase += delta; sphase = phase >> 24; @@ -112,16 +183,33 @@ AM::AM() { mode = Mode::AM; } -void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { int32_t sample = 0; int8_t re = 0, im = 0; - float q = 0.0; + float q = 0.0; for (size_t counter = 0; counter < buffer.count; counter++) { if (counter % 128 == 0) { sample = audio.p[counter / over] >> 2; + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. } + if (play_beep) { + sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message )<<5; // Apply beep -if selected - atom sample by sample. + } else { + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider *8); // Why ?orig / (new_divider / 4); // Why ? + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + } + q = sample / 32768.0f; q *= 256.0f; // Original 64.0f,now x4 (+12 dB's BB_modulation in AM & DSB) switch (mode) { diff --git a/firmware/baseband/dsp_modulate.hpp b/firmware/baseband/dsp_modulate.hpp index fdc6e95f..de964a68 100644 --- a/firmware/baseband/dsp_modulate.hpp +++ b/firmware/baseband/dsp_modulate.hpp @@ -24,6 +24,8 @@ #include "dsp_types.hpp" #include "dsp_hilbert.hpp" +#include "tone_gen.hpp" +#include "baseband_processor.hpp" namespace dsp { namespace modulate { @@ -41,13 +43,28 @@ enum class Mode { class Modulator { public: - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) = 0; + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer,bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) = 0; virtual ~Modulator(); Mode get_mode(); void set_mode(Mode new_mode); void set_over(uint32_t new_over); + void set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep ); + int32_t apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message ); + float audio_gain { }; + bool play_beep { false }; + uint32_t power_acc_count { 0 }; // this var it is initialized from Proc_mictx.cpp + uint32_t divider { }; // this var it is initialized from Proc_mictx.cpp + uint64_t power_acc { 0 }; // it is aux Accumulated sum (Absolute sample signal) , initialitzed to zero. + AudioLevelReportMessage level_message { }; + +private: + static constexpr size_t baseband_fs = 1536000U; + TXProgressMessage txprogress_message { }; + ToneGen beep_gen { }; + uint32_t beep_index { }, beep_timer { }; + protected: uint32_t over = 1; @@ -60,7 +77,7 @@ class SSB : public Modulator { public: SSB(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ); private: dsp::HilbertTransform hilbert; @@ -72,8 +89,9 @@ class FM : public Modulator { public: FM(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) ; void set_fm_delta(uint32_t new_delta); + void set_tone_gen_configure(const uint32_t delta, const float tone_mix_weight); /// @@ -81,13 +99,16 @@ private: uint32_t fm_delta { 0 }; uint32_t phase { 0 }, sphase { 0 }; int32_t sample { 0 }, delta { }; + ToneGen tone_gen { }; + + }; class AM : public Modulator { public: AM(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ); }; } /* namespace modulate */ diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index d5c0040c..6c9c9b97 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -35,8 +35,10 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ if (!configured) return; audio_input.read_audio_buffer(audio_buffer); - modulator->execute(audio_buffer, buffer); - + modulator->set_gain_vumeter_beep(audio_gain, play_beep ) ; + modulator->execute(audio_buffer, buffer, configured, beep_index, beep_timer, txprogress_message, level_message, power_acc_count, divider ); // Now "Key Tones & CTCSS" baseband additon inside FM mod. dsp_modulate.cpp" + + /* Original fw 1.3.1 good reference, beep and vu-meter for (size_t i = 0; i < buffer.count; i++) { if (!play_beep) { @@ -67,13 +69,13 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ beep_index++; } } - - sample = beep_gen.process(0); - } - - /* + sample = beep_gen.process(0); // TODO : Pending how to move inside modulate.cpp + } + */ + + /* Original fw 1.3.1 good reference FM moulation version, including "key tones CTCSS" fw 1.3.1 sample = tone_gen.process(sample); - + // FM if (configured) { delta = sample * fm_delta; @@ -89,8 +91,8 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ } buffer.p[i] = { re, im }; - */ - } + + } */ } void MicTXProcessor::on_message(const Message* const msg) { @@ -100,12 +102,16 @@ void MicTXProcessor::on_message(const Message* const msg) { switch(msg->id) { case Message::ID::AudioTXConfig: if (fm_enabled) { - dsp::modulate::FM *fm = new dsp::modulate::FM(); - - fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs)); + dsp::modulate::FM *fm = new dsp::modulate::FM(); + + // Config fm_delta private var inside DSP modulate.cpp + fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs)); + + // Config properly the private tone_gen function parameters inside DSP modulate.cpp + fm->set_tone_gen_configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); modulator = fm; } - + if (usb_enabled) { modulator = new dsp::modulate::SSB(); modulator->set_mode(dsp::modulate::Mode::USB); @@ -124,7 +130,7 @@ void MicTXProcessor::on_message(const Message* const msg) { modulator->set_mode(dsp::modulate::Mode::DSB); } - modulator->set_over(baseband_fs / 24000); + modulator->set_over(baseband_fs / 24000); // Keep no change. am_enabled = config_message.am_enabled; usb_enabled = config_message.usb_enabled; @@ -137,8 +143,9 @@ void MicTXProcessor::on_message(const Message* const msg) { audio_gain = config_message.audio_gain; divider = config_message.divider; power_acc_count = 0; - - tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); + + // now this config moved, in the case Message::ID::AudioTXConfig , only FM case. + // tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); txprogress_message.done = true; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index b26cae38..175e53c7 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -49,8 +49,8 @@ private: }; AudioInput audio_input { }; - ToneGen tone_gen { }; - ToneGen beep_gen { }; + // ToneGen tone_gen { }; moved to dsp_modulate.cpp + // ToneGen beep_gen { }; moved to dsp_modulate.cpp dsp::modulate::Modulator *modulator = NULL ; bool am_enabled { false }; diff --git a/firmware/baseband/spectrum_collector.cpp b/firmware/baseband/spectrum_collector.cpp index bdc5c77f..134de527 100644 --- a/firmware/baseband/spectrum_collector.cpp +++ b/firmware/baseband/spectrum_collector.cpp @@ -103,27 +103,13 @@ void SpectrumCollector::post_message(const buffer_c16_t& data) { } } -/* 3 types of Windowing time domain shapes declaration , but only used Hamming , shapes for FFT - GCC10 compile sintax error c/m (1/2), - The primary diff. between const and constexpr variables is that - the initialization of a const var can be deferred until run time. - A constexpr var. must be initialized at compile time. ... - A var. can be declared with constexpr , when it has a literal type and is initialized. - GCC compile sintax error c/m (2/2) - Static assert --> Tests a software assertion at compile time for debugging. - we keep the same safety compile protection , just changing slightly the sintax checking that the size of the called array is power of 2. - if the bool "constant expression" is TRUE (normal case) , the declaration has no effect. - if the bool "constant expression" is FALSE (abnormal array size) , it is aborted the compile with a msg error. - */ - - -template // Although currently we are not using that Windowing shape, we apply the same GCC10 compile error c/m +template static typename T::value_type spectrum_window_none(const T& s, const size_t i) { static_assert(power_of_two(ARRAY_ELEMENTS(s)), "Array number of elements must be power of 2"); // c/m compile error GCC10 , OK for all GCC versions. return s[i]; }; -template // Currently we are calling and using that Window shape. +template static typename T::value_type spectrum_window_hamming_3(const T& s, const size_t i) { static_assert(power_of_two(ARRAY_ELEMENTS(s)), "Array number of elements must be power of 2"); // c/m compile error GCC10 , OK for all GCC versions. const size_t mask = s.size() - 1; // c/m compile error GCC10 , constexpr->const @@ -131,7 +117,7 @@ static typename T::value_type spectrum_window_hamming_3(const T& s, const size_t return s[i] * 0.54f + (s[(i-1) & mask] + s[(i+1) & mask]) * -0.23f; }; -template // Although currently we are not using that Windowing shape, we apply the same GCC10 compile error c/m +template static typename T::value_type spectrum_window_blackman_3(const T& s, const size_t i) { static_assert(power_of_two(ARRAY_ELEMENTS(s)), "Array number of elements must be power of 2"); // c/m compile error GCC10 , OK for all GCC versions. const size_t mask = s.size() - 1; // c/m compile error GCC10 , constexpr->const diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index dd74579d..d015f94f 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -24,14 +24,20 @@ #include "sine_table_int8.hpp" +/* int32_t ToneGen::tone_sine() { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde + // Hoepfully we can manage without it , same as previous fw 1.3.1 int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000; tone_phase_ += delta_; return tone_sample; } +*/ + int32_t ToneGen::tone_square() { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde int32_t tone_sample = 0; if(tone_phase_ < (UINT32_MAX / 2)) { @@ -46,33 +52,66 @@ int32_t ToneGen::tone_square() { return tone_sample; } +/* void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { + // Confirmed ! It is not working well in the fw 1.4.4 Mic App , CTCSS generation, (but added for Sonde App) + // I Think it should be deleted or modified but not use it as it is in Mic App . + delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24); + delta_ = delta; tone_mix_weight_ = tone_mix_weight; input_mix_weight_ = 1.0 - tone_mix_weight; - current_tone_type_ = sine; } +*/ + + void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) { + // TODO : Added for Sonde App. We keep it by now to avoid compile errors, but it needs to be reviewed in Sonde delta_ = (uint8_t) ((freq * sizeof(sine_table_i8)) / sample_rate); tone_mix_weight_ = tone_mix_weight; input_mix_weight_ = 1.0 - tone_mix_weight; current_tone_type_ = tone_type; +} + + + + +// ----Original available core SW code from fw 1.3.1 , Working also well in Mic App CTCSS Gen from fw 1.4.0 onwards + +// Original direct-look-up synthesis algorithm with Fractional delta phase. It is OK +// Delta and Accumulator fase are stored in 32 bits (4 bytes), 1st top byte used as Modulo-256 Sine look-up table [index] +// the lower 3 bytes (24 bits) are used as a Fractional Detla and Accumulator phase, to have very finer Fstep control. + +void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { + delta_ = delta; + tone_mix_weight_ = tone_mix_weight; + input_mix_weight_ = 1.0 - tone_mix_weight; } int32_t ToneGen::process(const int32_t sample_in) { if (!delta_) return sample_in; - int32_t tone_sample = 0; - - if(current_tone_type_ == sine) { - tone_sample = tone_sine(); - } - else if(current_tone_type_ == square) { - tone_sample = tone_square(); - } + int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24]; + tone_phase_ += delta_; + + return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); +} +// ------------------------------------------------------------- + + + +int32_t ToneGen::process_square(const int32_t sample_in) { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde + if (!delta_) + return sample_in; + + int32_t tone_sample = 0; + + tone_sample = tone_square(); + return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); } diff --git a/firmware/baseband/tone_gen.hpp b/firmware/baseband/tone_gen.hpp index c1eee222..eca69e2f 100644 --- a/firmware/baseband/tone_gen.hpp +++ b/firmware/baseband/tone_gen.hpp @@ -28,7 +28,7 @@ class ToneGen { public: - enum tone_type { sine, square }; + enum tone_type { sine, square }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /*ToneGen(const size_t sample_rate ) : sample_rate_ { sample_rate } @@ -38,6 +38,7 @@ public: void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate); int32_t process(const int32_t sample_in); + int32_t process_square(const int32_t sample_in); private: tone_type current_tone_type_ { sine }; @@ -45,19 +46,23 @@ private: float input_mix_weight_ { 1 }; float tone_mix_weight_ { 0 }; - uint8_t delta_ { 0 }; - uint8_t tone_phase_ { 0 }; + uint32_t delta_ { 0 }; + uint32_t tone_phase_ { 0 }; + +// uint8_t delta_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. +// uint8_t tone_phase_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /** * Generator function which selects every other sample from the reference sine waveform to the output sample: */ - int32_t tone_sine(); + int32_t tone_sine();// TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /** * Generator function for square waves: */ - int32_t tone_square(); + int32_t tone_square(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. + }; #endif /* __TONE_GEN_H__ */ diff --git a/firmware/common/ak4951.cpp b/firmware/common/ak4951.cpp index 1f88a3d6..74301ecb 100644 --- a/firmware/common/ak4951.cpp +++ b/firmware/common/ak4951.cpp @@ -216,347 +216,90 @@ void AK4951::speaker_disable() { set_speaker_power(false); } -void AK4951::microphone_enable(int8_t alc_mode) { -// alc_mode =0 = (OFF =same as original code = NOT using AK4951 Programmable digital filter block), -// alc_mode >1 (with DIGITAL FILTER BLOCK , example : 1:(+12dB) , 2:(+9dB)", 3:(+6dB), ...) - -// map.r.digital_mic.DMIC = 0; // originally commented code -// update(Register::DigitalMic); // originally commented code - -uint_fast8_t mgain =0b0111; // Pre-amp mic (Original code, =0b0111 (+21dB's=7x3dBs),(Max is NOT 0b1111!, it is 0b1010=+30dBs=10x3dBs) - -map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 , our ext. MONO MIC is connected here LIN2 in Portapack. -map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 , Not used ,not connected ,but no problem. -map.r.signal_select_2.MICL = 0; // MPWR = 2.4V (it has two possible settings , 2.4V or 2.0V) , (majority smarthphones around 2V , range 1V-5V) -update(Register::SignalSelect2); - -// ------Common code part, = original setting conditions, it is fine for all user-GUI alc_modes: OFF , and ALC modes .*/ -map.r.digital_filter_select_1.HPFAD = 1; // HPF1 ON (after ADC);page 40 datasheet, HPFAD bit controls the ON/OFF of the HPF1 (HPF ON is recommended). -map.r.digital_filter_select_1.HPFC = 0b11; // HPF Cut off frequency of high pass filter from 236.8 Hz @fs=48k ("00":3.7Hz, "01":14,8Hz, "10":118,4Hz) -update(Register::DigitalFilterSelect1); - -// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB., (not used by now , original code cond.) -// update(Register::RchMicGainSetting); // (those two lines , not activated, same as original) - -// pre-load 4 byes LPF coefficicients (.lpf_coefficient_0,1,2,3), FSA 14..0, FSB 14..0 , (fcut initial 6kHz, fs 48Khz). -// it will be default pre-loading coeff. for al ALC modes, LPF bit is activated down, for all ALC digital modes. -map.r.lpf_coefficient_0.l = 0x5F; // Pre-loading here LPF 6kHz, 1st Order from digital Block , Fc=6000 Hz, fs = 48khz -map.r.lpf_coefficient_1.h = 0x09; // LPF bit is activated down, for all ALC digital modes. -map.r.lpf_coefficient_2.l = 0xBF; // Writting reg to AK4951, with "update", following instructions. -map.r.lpf_coefficient_3.h = 0x32; - -update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 -update(Register::LPFCoefficient1); // In this case , LPF 6KHz , when we activate the LPF block. -update(Register::LPFCoefficient2); -update(Register::LPFCoefficient3); - -// Reset , setting OFF all 5 x Digital Equalizer filters -map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled -map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled -map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled -map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled -map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled -update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp - - - if (alc_mode==0) { // Programmable Digital Filter OFF, same as original condition., no Digital ALC, nor Wind Noise Filter, LPF , EQ - - map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - update(Register::DigitalFilterSelect2); - - // Pre-loading AUDIO PATH with all DIGITAL BLOCK by pased, see, audio path block diagramm AK4951 datasheet + Table Playback mode -Recording mode. - // Digital filter block PATH is BY PASSED (we can swith off DIG. BLOCK power , PMPFIL=0) .The Path in Recording Mode 2 & Playback Mode 2 (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback) - map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 0; // ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block . - map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management - map.r.power_management_1.PMPFIL = 0; // Pre-loading , Programmable Dig. filter OFF ,filter unused, routed around.(original value = 0 ) - update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) - - // 1059/fs, 22ms @ 48kHz - chThdSleepMilliseconds(22); - - } else { // ( alc_mode !=0) - - switch(alc_mode) { // Pre-loading register values depending on user-GUI selection (they will be sended below, with "update(Register_name::xxx )". - - case 1: // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xC0; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, C0H=+12dBs) - map.r.l_ch_input_volume_control.IV = 0xC0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xC0; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 2: // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xB8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B8H= +9dBs) - map.r.l_ch_input_volume_control.IV = 0xB8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xB8; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 3: // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xB0; // 0xB8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B0H= +6dBs) - map.r.l_ch_input_volume_control.IV = 0xB0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xB0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 4: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original) - // + EQ boosting ~<2kHz (f0:1,1k, fb:1,7K, k=1,8) && + LPF 3,5k - map.r.alc_mode_control_2.REF = 0xA8; // 0xA8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - //The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”. - map.r.digital_filter_select_3.EQ1 = 1; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled - update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp - - map.r.lpf_coefficient_0.l = 0x0D; // Pre-loading here LPF 3,5k , 1st Order from digital Block , Fc=3.500 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x1A; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x2C; - // LPF bit is activated down, for all ALC digital modes. - break; - - case 5: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original) - // + EQ boosting ~<3kHz (f0~1k4,fb~2,4k,k=1,8) && LPF 4kHz - map.r.alc_mode_control_2.REF = 0xA8; // 0xA0 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - map.r.digital_filter_select_3.EQ2 = 1; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled - update(Register::DigitalFilterSelect3); - - map.r.lpf_coefficient_0.l = 0xC3; // Pre-loading here LPF 4k , 1st Order from digital Block , Fc=4000 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x86; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x2D; - // LPF bit is activated down, for all ALC digital modes. - break; - - case 6: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xA8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 7: // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xA0; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs) - map.r.l_ch_input_volume_control.IV = 0xA0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 8: // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0x98; //REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 98H=-03dBs) - map.r.l_ch_input_volume_control.IV = 0x98; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x98; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s +void AK4951::microphone_enable() { +// map.r.digital_mic.DMIC = 0; +// update(Register::DigitalMic); - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; + const uint_fast8_t mgain = 0b0111; + map.r.signal_select_1.MGAIN20 = mgain & 7; + map.r.signal_select_1.PMMP = 1; + map.r.signal_select_1.MPSEL = 1; // MPWR2 pin + map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; + update(Register::SignalSelect1); - case 9: // ALC-> on, (-06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0x90; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 90H=-06dBs) - map.r.l_ch_input_volume_control.IV = 0x90; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x90; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s + map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 + map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 + map.r.signal_select_2.MICL = 0; // MPWR = 2.4V + update(Register::SignalSelect2); - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 10: // ALC-> on, (-09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -3dB (18dB's) - // Reduce also Pre-amp Mic -3dB's (+18dB's) - mgain = 0b0110; // Pre-amp mic Mic Gain Pre-amp (+18dB), Original=0b0111 (+21dB's =7x3dBs), - - map.r.alc_mode_control_2.REF = 0x88; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 88H=-09dBs) - map.r.l_ch_input_volume_control.IV = 0x88; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x88; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 11: // ALC-> on, (-12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -6dB (15dB's) - // Reduce also Pre-amp Mic -6dB's (+15dB's) - mgain = 0b0101; // Pre-amp mic Mic Gain Pre-amp (+15dB), (Original=0b0111 (+21dB's= 7x3dBs), - - map.r.alc_mode_control_2.REF = 0x80; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 80H=-12dBs) - map.r.l_ch_input_volume_control.IV = 0x80; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x80; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - } - - //-------------------------------DIGITAL ALC (Automatic Level Control ) --- -------- - map.r.alc_mode_control_1.ALC = 0; // LMTH2-0, WTM1-0, RGAIN2-0, REF7-0, RFST1-0, EQFC1-0, FRATT, FRN and ALCEQN bits (needs to be set up with ALC disable = 0) - update(Register::ALCModeControl1); - - map.r.timer_select.FRN = 0; // (FRN= 0 Fast Recovery mode , enable ) - map.r.timer_select.FRATT = 0; // Fast Recovery Ref. Volume Atten. Amount -0,00106dB's, timing 4/fs (default) - map.r.timer_select.ADRST = 0b00; // initial offset ADC cycles , 22ms @fs=48Khz. +// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB. +// update(Register::RchMicGainSetting); +/* + map.r.timer_select.FRN = ?; + map.r.timer_select.FRATT = ?; + map.r.timer_select.ADRST = 0b??; update(Register::TimerSelect); - map.r.alc_timer_select.RFST = 0b00; // RFST1-0: ALC Fast Recovery Speed Default: “00” (0.0032dB) - map.r.alc_timer_select.WTM = 0b00; // ALC Recovery Operation Waiting Period 128/fs = 2,7 mseg (min=default) - map.r.alc_timer_select.EQFC = 0b10; // Selecting default, fs 48Khz , ALCEQ: First order zero pole high pass filter fc2=100Hz, fc1=150Hz - map.r.alc_timer_select.IVTM = 0; // IVTM bit set the vol transition time ,236/fs = 4,9msecs (min) (default was 19,7msegs.) + map.r.alc_timer_select. = ?; update(Register::ALCTimerSelect); - - map.r.alc_mode_control_1.LMTH10 = 0b11; // ALC Limiter Detec Level/ Recovery Counter Reset; lower 2 bits (Ob111=-8,4dbs), (default 0b000=-2,5dBs) - map.r.alc_mode_control_1.RGAIN = 0b000; // ALC Recovery Gain Step, max step , max speed. Default: “000” (0.00424dB) - map.r.alc_mode_control_1.ALC = 1; // ALC Enable . (we are now, NOT in MANUAL volume mode, only becomes manual when (ALC=“0” while ADCPF=“1”. ) - map.r.alc_mode_control_1.LMTH2 = 1; // ALC Limiter Detection Level/ Recovery Counter Reset Level,Upper bit,default 0b000 - map.r.alc_mode_control_1.ALCEQN = 1; // ALC EQ Off =1 not used by now, 0: ALC EQ On (default) + map.r.alc_mode_control_1. = ?; + map.r.alc_mode_control_1.ALC = 1; update(Register::ALCModeControl1); - // map.r.alc_mode_control_2.REF = 0x??; // Pre-loaded in top part. Maximum gain at ALC recovery operation,.(FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) + map.r.alc_mode_control_2.REF = ?; update(Register::ALCModeControl2); - - // map.r.l_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - update(Register::LchInputVolumeControl); - - // map.r.r_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Right,Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - update(Register::RchInputVolumeControl); - - - //---------------Switch ON, Digital Automatic Wind Noise Filter reduction ------------------- - // Difficult to realise that Dynamic HPF Wind noise filter benefit, maybe because we have another fixed HPF 236.8 Hz . - // Anyway , we propose to activate it , with default setting conditions. - map.r.power_management_1.PMPFIL = 0; // (*1) To programm SENC, STG , we need PMPFIL = 0 . (but this disconnect Digital block power supply. - update(Register::PowerManagement1); // Updated PMPFIL to 0 . (*1) - - map.r.auto_hpf_control.STG = 0b00; // (00=LOW ATTENUATION Level), lets put 11 (HIGH ATTENUATION Level) (default 00) - map.r.auto_hpf_control.SENC = 0b011; // (000=LOW sensitivity detection)… 111((MAX sensitivity detection) (default 011) - map.r.auto_hpf_control.AHPF = 1; // Autom. Wind noise filter ON (AHPF bit=“1”).It atten. wind noise when detecting ,and adjusts the atten. level dynamically. - update(Register::AutoHPFControl); - - // We are in Digital Block ON , (Wind Noise Filter+ALC+LPF+EQ),==> needs at the end , PMPFIL=1 , Program. Dig.filter ON - // map.r.power_management_1.PMPFIL = 1; // that instruction is at the end , we can skp pre-loading Programmable Dig. filter ON (*1) - //--------------------------------------------------------------------- - - // Writing AUDIO PATH diagramm, Changing Audio mode path : Playback mode1 /-Recording mode2. (Figure 37 AK4951 datasheet, Table 27. Recording Playback Mode) - // When changing those modes, PMPFIL bit must be “0”, it is OK (*1) - map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 1; // ADC (+ 1st order HPF) Output - map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - // The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”., but we are already (*1) - // map.r.power_management_1.PMPFIL = 0; // In the previous Wind Noise Filter , we already set up PPFIL = 0 - // update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) - - // ... Set EQ & LPF coefficients --------------------------------- - - // writting to the IC ak4951 reg. settings defined in Ak4951.hpp , the 30 bytes , EQ coefficient = 5 (EQ1,2,3,4,5) x 3 (A,B,C coefficients) x 2 bytes (16 bits) - update(Register::E1Coefficient0); // we could pre-load here,ex ,"map.r.e1_coefficient_0.l = 0x50;" , EQ1 Coefficient A : A7...A0, but already done in ak4951.hpp - update(Register::E1Coefficient1); // we could pre-load here,ex ,"map.r.e1_coefficient_1.h = 0xFE;" , EQ1 Coefficient A : A15..A8, " " - update(Register::E1Coefficient2); // we could pre-load here,ex ,"map.r.e1_coefficient_2.l = 0x29;" , EQ1 Coefficient B : B7...B0, " " - update(Register::E1Coefficient3); // we could pre-load here,ex ,"map.r.e1_coefficient_3.h = 0xC5;" , EQ1 Coefficient B : B15..B8, " " - update(Register::E1Coefficient4); // we could pre-load here,ex ,"map.r.e1_coefficient_4.l = 0xA0;" , EQ1 Coefficient C : C7...C0, " " - update(Register::E1Coefficient5); // we could pre-load here,ex ,"map.r.e1_coefficient_5.h = 0x1C;" , EQ1 Coefficient C : C15..C8, " " - - update(Register::E2Coefficient0); // writing pre-loaded EQ2 coefficcients - update(Register::E2Coefficient1); - update(Register::E2Coefficient2); - update(Register::E2Coefficient3); - update(Register::E2Coefficient4); - update(Register::E2Coefficient5); - - // Already pre-loaded LPF coefficients to 6k, 3,5k or 4k ,(LPF 6Khz all digital alc modes top , except when 3k5 , 4k) - update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 - update(Register::LPFCoefficient1); - update(Register::LPFCoefficient2); - update(Register::LPFCoefficient3); - - // Activating LPF block , (and re-configuring the rest of bits of the same register) - map.r.digital_filter_select_2.HPF = 0; // HPF2-Block, Coeffic Setting Enable (OFF-Default), When HPF bit is “0”, audio data passes the HPF2 block by is 0dB gain. - map.r.digital_filter_select_2.LPF = 1; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - map.r.digital_filter_select_2.FIL3 = 0; // Stereo_Emphasis_Filter-Block,(OFF-Default) Coefficient Setting Enable , OFF , Disable. - map.r.digital_filter_select_2.EQ0 = 0; // Gain Compensation-Block, (OFF-Default) Coeffic Setting Enable, When EQ0 bit = “0” audio data passes the EQ0 block by 0dB gain. - map.r.digital_filter_select_2.GN = 0b00; // Gain Setting of the Gain Compensation Block Default: “00”-Default (0dB) +*/ +// map.r.l_ch_input_volume_control.IV = 0xe1; +// update(Register::LchInputVolumeControl); +// map.r.r_ch_input_volume_control.IV = 0xe1; +// update(Register::RchInputVolumeControl); +/* + map.r.auto_hpf_control.STG = 0b00; + map.r.auto_hpf_control.SENC = 0b011; + map.r.auto_hpf_control.AHPF = 0; + update(Register::AutoHPFControl); +*/ + map.r.digital_filter_select_1.HPFAD = 1; // HPF1 (after ADC) = on + map.r.digital_filter_select_1.HPFC = 0b11; // 2336.8 Hz @ fs=48k + update(Register::DigitalFilterSelect1); +/* + map.r.digital_filter_select_2.HPF = 0; + map.r.digital_filter_select_2.LPF = 0; + map.r.digital_filter_select_2.FIL3 = 0; + map.r.digital_filter_select_2.EQ0 = 0; + map.r.digital_filter_select_2.GN = 0b00; update(Register::DigitalFilterSelect2); - // Acitivating digital block , power supply - map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management - map.r.power_management_1.PMPFIL = 1; // Pre-loaded in top part. Orig value=0, Programmable Digital filter unused (not power up), routed around. - update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) + map.r.digital_filter_select_3.EQ1 = 0; + map.r.digital_filter_select_3.EQ2 = 0; + map.r.digital_filter_select_3.EQ3 = 0; + map.r.digital_filter_select_3.EQ4 = 0; + map.r.digital_filter_select_3.EQ5 = 0; + update(Register::DigitalFilterSelect3); +*/ + map.r.digital_filter_mode.PFSDO = 0; // ADC (+ 1st order HPF) Output + map.r.digital_filter_mode.ADCPF = 1; // ADC Output (default) + update(Register::DigitalFilterMode); + + // ... Set coefficients ... + + map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal + map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal + map.r.power_management_1.PMPFIL = 0; // Programmable filter unused, routed around. + update(Register::PowerManagement1); // 1059/fs, 22ms @ 48kHz chThdSleepMilliseconds(22); - - } - - // Common part for all alc_mode , -------------------------- - // const uint_fast8_t mgain = 0b0111; // Already pre-loaded , in above switch case . - map.r.signal_select_1.MGAIN20 = mgain & 7; // writing 3 lower bits of mgain , (pre-amp mic gain). - map.r.signal_select_1.PMMP = 1; // Activating DC Mic Power supply through 2kohms res., similar majority smartphones headphone+mic jack, "plug-in-power" - map.r.signal_select_1.MPSEL = 1; // MPWR2 pin ,selecting output voltage to MPWR2 pin, that we are using in portapack ext. MIC) - map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; // writing 4th upper bit of mgain (pre-amp mic gain). - update(Register::SignalSelect1); - } - - void AK4951::microphone_disable() { - map.r.power_management_1.PMADL = 0; // original code , disable Power managem.Mic ADC L - map.r.power_management_1.PMADR = 0; // original code , disable Power managem.Mic ADC R - map.r.power_management_1.PMPFIL = 0; // original code , disable Power managem. all Programmable Dig. block + map.r.power_management_1.PMADL = 0; + map.r.power_management_1.PMADR = 0; + map.r.power_management_1.PMPFIL = 0; update(Register::PowerManagement1); - map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block. + map.r.alc_mode_control_1.ALC = 0; update(Register::ALCModeControl1); - - map.r.auto_hpf_control.AHPF = 0; //----------- new code addition , Restore disable Wind noise filter OFF (AHPF bit=“0”). - update(Register::AutoHPFControl); - - //Restore original AUDIO PATH , condition, (Digital filter block PATH is BY PASSED) (we can also swith off DIG. BLOCK power , PMPFIL=0) - // The Path in Recording Mode 2 & Playback Mode 2 , (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback) - map.r.digital_filter_mode.ADCPF = 1; // new code addition , ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 0; // new code addition , ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block . - map.r.digital_filter_mode.PFDAC = 0b00; // new code addition , (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - // Restore original condition , LPF , OFF . same as when not using DIGITAL Programmable block - map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - update(Register::DigitalFilterSelect2); - - map.r.lpf_coefficient_0.l = 0x00; // Pre-loading here LPF 6k , 1st Order from digital Block , Fc=6000 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x00; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x00; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x00; - - update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 - update(Register::LPFCoefficient1); - update(Register::LPFCoefficient2); - update(Register::LPFCoefficient3); - - // Switch off all EQ 1,2,3,4,5 - map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled - map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled - map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled - map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled - map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled - update(Register::DigitalFilterSelect3); - } reg_t AK4951::read(const address_t reg_address) { diff --git a/firmware/common/ak4951.hpp b/firmware/common/ak4951.hpp index 3b1f9e1a..df168a09 100644 --- a/firmware/common/ak4951.hpp +++ b/firmware/common/ak4951.hpp @@ -773,41 +773,40 @@ constexpr RegisterMap default_after_reset { Register_Type { .REV = 0b1100, }, - // just pre-loading into memory, 30 bytes = EQ 1,2,3,4,5 x A,B,C (2 x bytes) coefficients, but it will be written from ak4951.cpp - .e1_coefficient_0 = { .l = 0xCA }, //EQ1 Coefficient A : A7...A0, BW : 300Hz - 1700Hz (fo = 1150Hz , fb= 1700Hz) , k=1,8 peaking - .e1_coefficient_1 = { .h = 0x05 }, //EQ1 Coefficient A : A15..A8 - .e1_coefficient_2 = { .l = 0xEB }, //EQ1 Coefficient B : B7...B0 - .e1_coefficient_3 = { .h = 0x38 }, //EQ1 Coefficient B : B15...B8 - .e1_coefficient_4 = { .l = 0x6F }, //EQ1 Coefficient C : C7...C0 - .e1_coefficient_5 = { .h = 0xE6 }, //EQ1 Coefficient C : C15..C8 + .e1_coefficient_0 = { .l = 0x00 }, + .e1_coefficient_1 = { .h = 0x00 }, + .e1_coefficient_2 = { .l = 0x00 }, + .e1_coefficient_3 = { .h = 0x00 }, + .e1_coefficient_4 = { .l = 0x00 }, + .e1_coefficient_5 = { .h = 0x00 }, - .e2_coefficient_0 = { .l = 0x05 }, //EQ2 Coefficient A : A7...A0, BW : 250Hz - 2700Hz (fo = 1475Hz , fb= 2450Hz) , k=1,8 peaking - .e2_coefficient_1 = { .h = 0x08 }, //EQ2 Coefficient A : A15..A8 - .e2_coefficient_2 = { .l = 0x11 }, //EQ2 Coefficient B : B7...B0 - .e2_coefficient_3 = { .h = 0x36 }, //EQ2 Coefficient B : B15...B8 - .e2_coefficient_4 = { .l = 0xE9 }, //EQ2 Coefficient C : C7...C0 - .e2_coefficient_5 = { .h = 0xE8 }, //EQ2 Coefficient C : C15..C8 + .e2_coefficient_0 = { .l = 0x00 }, + .e2_coefficient_1 = { .h = 0x00 }, + .e2_coefficient_2 = { .l = 0x00 }, + .e2_coefficient_3 = { .h = 0x00 }, + .e2_coefficient_4 = { .l = 0x00 }, + .e2_coefficient_5 = { .h = 0x00 }, - .e3_coefficient_0 = { .l = 0x00 }, //EQ3 Coefficient A : A7...A0, not used currently - .e3_coefficient_1 = { .h = 0x00 }, //EQ3 Coefficient A : A15..A8 - .e3_coefficient_2 = { .l = 0x00 }, //EQ3 Coefficient B : B7...B0 - .e3_coefficient_3 = { .h = 0x00 }, //EQ3 Coefficient B : B15...B8 - .e3_coefficient_4 = { .l = 0x00 }, //EQ3 Coefficient C : C7...C0 - .e3_coefficient_5 = { .h = 0x00 }, //EQ3 Coefficient C : C15..C8 + .e3_coefficient_0 = { .l = 0x00 }, + .e3_coefficient_1 = { .h = 0x00 }, + .e3_coefficient_2 = { .l = 0x00 }, + .e3_coefficient_3 = { .h = 0x00 }, + .e3_coefficient_4 = { .l = 0x00 }, + .e3_coefficient_5 = { .h = 0x00 }, - .e4_coefficient_0 = { .l = 0x00 }, //EQ4 Coefficient A : A7...A0, not used currently - .e4_coefficient_1 = { .h = 0x00 }, //EQ4 Coefficient A : A15..A8 - .e4_coefficient_2 = { .l = 0x00 }, //EQ4 Coefficient B : B7...B0 - .e4_coefficient_3 = { .h = 0x00 }, //EQ4 Coefficient B : B15...B8 - .e4_coefficient_4 = { .l = 0x00 }, //EQ4 Coefficient C : C7...C0 - .e4_coefficient_5 = { .h = 0x00 }, //EQ4 Coefficient C : C15..C8 + .e4_coefficient_0 = { .l = 0x00 }, + .e4_coefficient_1 = { .h = 0x00 }, + .e4_coefficient_2 = { .l = 0x00 }, + .e4_coefficient_3 = { .h = 0x00 }, + .e4_coefficient_4 = { .l = 0x00 }, + .e4_coefficient_5 = { .h = 0x00 }, - .e5_coefficient_0 = { .l = 0x00 }, //EQ5 Coefficient A : A7...A0, not used currently - .e5_coefficient_1 = { .h = 0x00 }, //EQ5 Coefficient A : A15..A8 - .e5_coefficient_2 = { .l = 0x00 }, //EQ5 Coefficient B : B7...B0 - .e5_coefficient_3 = { .h = 0x00 }, //EQ5 Coefficient B : B15...B8 - .e5_coefficient_4 = { .l = 0x00 }, //EQ5 Coefficient C : C7...C0 - .e5_coefficient_5 = { .h = 0x00 }, //EQ5 Coefficient C : C15..C8 + .e5_coefficient_0 = { .l = 0x00 }, + .e5_coefficient_1 = { .h = 0x00 }, + .e5_coefficient_2 = { .l = 0x00 }, + .e5_coefficient_3 = { .h = 0x00 }, + .e5_coefficient_4 = { .l = 0x00 }, + .e5_coefficient_5 = { .h = 0x00 }, } }; class AK4951 : public audio::Codec { @@ -842,7 +841,7 @@ public: void set_headphone_volume(const volume_t volume) override; void headphone_mute(); - void microphone_enable(int8_t alc_mode); // added user GUI parameter , to set up AK4951 ALC mode. + void microphone_enable(); void microphone_disable(); size_t reg_count() const override { diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 1b577336..e226b4b7 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -28,7 +28,8 @@ #include "utility.hpp" #include "memory_map.hpp" -using portapack::memory::map::backup_ram; + +#include "crc.hpp" #include #include @@ -67,8 +68,193 @@ using clkout_freq_range_t = range_t; 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, +}; + +static const uint32_t TOUCH_CALIBRATION_MAGIC = 0x074af82f; + +struct ui_config_t { +private: + enum bits_t { + BacklightTimeoutLSB = 0, + BacklightTimeoutEnable = 3, + ClkoutFreqLSB = 4, + ShowGUIReturnIcon = 20, + LoadAppSettings = 21, + SaveAppSettings = 22, + ShowBiggerQRCode = 23, + DisableTouchscreen = 24, + HideClock = 25, + ClockWithDate = 26, + ClkOutEnabled = 27, + ConfigSpeaker = 28, + StealthMode = 29, + ConfigLogin = 30, + ConfigSplash = 31, + }; + + enum bits_mask_t : uint32_t { + BacklightTimeoutMask = ((1 << 3) - 1) << bits_t::BacklightTimeoutLSB, + ClkoutFreqMask = ((1 << 16) - 1) << bits_t::ClkoutFreqLSB, + }; + + uint32_t values; + + constexpr bool bit_read(const bits_t n) const { + return ((values >> n) & 1) != 0; + } + + constexpr void bit_write(const bits_t n, const bool v) { + if(bit_read(n) != v) { + values ^= 1 << n; + } + } + +public: + backlight_config_t config_backlight_timer() { + const auto timeout_enum = (backlight_timeout_t)((values & bits_mask_t::BacklightTimeoutMask) >> bits_t::BacklightTimeoutLSB); + const bool timeout_enabled = bit_read(bits_t::BacklightTimeoutEnable); + return backlight_config_t(timeout_enum, timeout_enabled); + } + + void set_config_backlight_timer(const backlight_config_t& new_value) { + values = (values & ~bits_mask_t::BacklightTimeoutMask) + | ((new_value.timeout_enum() << bits_t::BacklightTimeoutLSB) & bits_mask_t::BacklightTimeoutMask); + bit_write(bits_t::BacklightTimeoutEnable, new_value.timeout_enabled()); + } + + constexpr uint32_t clkout_freq() { + uint32_t freq = (values & bits_mask_t::ClkoutFreqMask) >> bits_t::ClkoutFreqLSB; + if(freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) { + values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_reset_value << bits_t::ClkoutFreqLSB); + return clkout_freq_reset_value; + } + else { + return freq; + } + } + + constexpr void set_clkout_freq(uint32_t freq) { + values = (values & ~bits_mask_t::ClkoutFreqMask) | (clkout_freq_range.clip(freq) << bits_t::ClkoutFreqLSB); + } + + // ui_config is an uint32_t var storing information bitwise + // bits 0-2 store the backlight timer + // bits 4-19 (16 bits) store the clkout frequency + // bits 21-31 store the different single bit configs depicted below + // bit 20 store the display state of the gui return icon, hidden (0) or shown (1) + + constexpr bool show_gui_return_icon() const { // add return icon in touchscreen menue + return bit_read(bits_t::ShowGUIReturnIcon); + } + + constexpr void set_gui_return_icon(bool v) { + bit_write(bits_t::ShowGUIReturnIcon, v); + } + + constexpr bool load_app_settings() const { // load (last saved) app settings on startup of app + return bit_read(bits_t::LoadAppSettings); + } + + constexpr void set_load_app_settings(bool v) { + bit_write(bits_t::LoadAppSettings, v); + } + + constexpr bool save_app_settings() const { // save app settings when closing app + return bit_read(bits_t::SaveAppSettings); + } + + constexpr void set_save_app_settings(bool v) { + bit_write(bits_t::SaveAppSettings, v); + } + + constexpr bool show_bigger_qr_code() const { // show bigger QR code + return bit_read(bits_t::ShowBiggerQRCode); + } + + constexpr void set_show_bigger_qr_code(bool v) { + bit_write(bits_t::ShowBiggerQRCode, v); + } + + constexpr bool disable_touchscreen() const { // Option to disable touch screen + return bit_read(bits_t::DisableTouchscreen); + } + + constexpr void set_disable_touchscreen(bool v) { + bit_write(bits_t::DisableTouchscreen, v); + } + + constexpr bool hide_clock() const { // clock hidden from main menu + return bit_read(bits_t::HideClock); + } + + constexpr void set_clock_hidden(bool v) { + bit_write(bits_t::HideClock, v); + } + + constexpr bool clock_with_date() const { // show clock with date, if not hidden + return bit_read(bits_t::ClockWithDate); + } + + constexpr void set_clock_with_date(bool v) { + bit_write(bits_t::ClockWithDate, v); + } + + constexpr bool clkout_enabled() const { + return bit_read(bits_t::ClkOutEnabled); + } + + constexpr void set_clkout_enabled(bool v) { + bit_write(bits_t::ClkOutEnabled, v); + } + + constexpr bool config_speaker() const { + return bit_read(bits_t::ConfigSpeaker); + } + + constexpr void set_config_speaker(bool v) { + bit_write(bits_t::ConfigSpeaker, v); + } + + constexpr bool stealth_mode() const { + return bit_read(bits_t::StealthMode); + } + + constexpr void set_stealth_mode(bool v) { + bit_write(bits_t::StealthMode, v); + } + + constexpr bool config_login() const { + return bit_read(bits_t::ConfigLogin); + } + + constexpr void set_config_login(bool v) { + bit_write(bits_t::ConfigLogin, v); + } + + constexpr bool config_splash() const { + return bit_read(bits_t::ConfigSplash); + } + + constexpr void set_config_splash(bool v) { + bit_write(bits_t::ConfigSplash, v); + } + + constexpr ui_config_t() : + values( + (1 << ConfigSplash) + | (1 << ConfigSpeaker) + | (clkout_freq_reset_value << ClkoutFreqLSB) + | (7 << BacklightTimeoutLSB) + ) + { + } +}; + /* struct must pack the same way on M4 and M0 cores. */ struct data_t { + data_structure_version_enum structure_version; int64_t tuned_frequency; int32_t correction_ppb; uint32_t touch_calibration_magic; @@ -89,7 +275,7 @@ struct data_t { uint32_t playdead_sequence; // UI - uint32_t ui_config; + ui_config_t ui_config; uint32_t pocsag_last_address; uint32_t pocsag_ignore_address; @@ -98,11 +284,142 @@ struct data_t { // Hardware uint32_t hardware_config; + + constexpr data_t() : + structure_version(data_structure_version_enum::VERSION_CURRENT), + tuned_frequency(tuned_frequency_reset_value), + correction_ppb(ppb_reset_value), + touch_calibration_magic(TOUCH_CALIBRATION_MAGIC), + touch_calibration(touch::Calibration()), + + modem_def_index(0), // TODO: Unused? + serial_format(), + modem_bw(15000), // TODO: Unused? + afsk_mark_freq(afsk_mark_reset_value), + afsk_space_freq(afsk_space_reset_value), + modem_baudrate(modem_baudrate_reset_value), + modem_repeat(modem_repeat_reset_value), + + playdead_magic(), // TODO: Unused? + playing_dead(), // TODO: Unused? + playdead_sequence(), // TODO: Unused? + + ui_config(), + + pocsag_last_address(0), // TODO: A better default? + pocsag_ignore_address(0), // TODO: A better default? + + tone_mix(tone_mix_reset_value), + + hardware_config(0) + { + } }; -static_assert(sizeof(data_t) <= backup_ram.size(), "Persistent memory structure too large for VBAT-maintained region"); +struct backup_ram_t { +private: + uint32_t regfile[63]; + uint32_t check_value; -static data_t* const data = reinterpret_cast(backup_ram.base()); + static void copy(const backup_ram_t& src, backup_ram_t& dst) { + for(size_t i=0; i<63; i++) { + dst.regfile[i] = src.regfile[i]; + } + dst.check_value = src.check_value; + } + + static void copy_from_data_t(const data_t& src, backup_ram_t& dst) { + const uint32_t* const src_words = (uint32_t*)&src; + const size_t word_count = (sizeof(data_t) + 3) / 4; + for(size_t i=0; i<63; i++) { + if(i crc { 0x04c11db7, 0xffffffff, 0xffffffff }; + for(size_t i=0; i<63; i++) { + const auto word = regfile[i]; + crc.process_byte((word >> 0) & 0xff); + crc.process_byte((word >> 8) & 0xff); + crc.process_byte((word >> 16) & 0xff); + crc.process_byte((word >> 24) & 0xff); + } + return crc.checksum(); + } + +public: + /* default constructor */ + backup_ram_t() : + check_value(0) + { + const data_t defaults = data_t(); + copy_from_data_t(defaults, *this); + } + + /* copy-assignment operator */ + backup_ram_t& operator=(const backup_ram_t& src) { + copy(src, *this); + return *this; + } + + /* Calculate a check value from `this`, and check against + * the stored value. + */ + bool is_valid() { + return compute_check_value() == check_value; + } + + /* Assuming `this` contains valid data, update the checksum + * and copy to the destination. + */ + void persist_to(backup_ram_t& dst) { + check_value = compute_check_value(); + copy(*this, dst); + } +}; + +static_assert(sizeof(backup_ram_t) == memory::map::backup_ram.size()); +static_assert(sizeof(data_t) <= sizeof(backup_ram_t) - sizeof(uint32_t)); + +static backup_ram_t* const backup_ram = reinterpret_cast(memory::map::backup_ram.base()); + +static backup_ram_t cached_backup_ram; +static data_t* const data = reinterpret_cast(&cached_backup_ram); + +namespace cache { + +void defaults() { + cached_backup_ram = backup_ram_t(); +} + +void init() { + if(backup_ram->is_valid()) { + // Copy valid persistent data into cache. + cached_backup_ram = *backup_ram; + + // Check that structure data we copied into cache is the expected + // version. If not, initialize cache to defaults. + if(data->structure_version != data_structure_version_enum::VERSION_CURRENT) { + // TODO: Can provide version-to-version upgrade functions here, + // if we want to be fancy. + defaults(); + } + } else { + // Copy defaults into cache. + defaults(); + } +} + +void persist() { + cached_backup_ram.persist_to(*backup_ram); +} + +} /* namespace cache */ rf::Frequency tuned_frequency() { rf::tuning_range.reset_if_outside(data->tuned_frequency, tuned_frequency_reset_value); @@ -124,16 +441,14 @@ void set_correction_ppb(const ppb_t new_value) { portapack::clock_manager.set_reference_ppb(clipped_value); } -static constexpr uint32_t touch_calibration_magic = 0x074af82f; - void set_touch_calibration(const touch::Calibration& new_value) { data->touch_calibration = new_value; - data->touch_calibration_magic = touch_calibration_magic; + data->touch_calibration_magic = TOUCH_CALIBRATION_MAGIC; } const touch::Calibration& touch_calibration() { - if( data->touch_calibration_magic != touch_calibration_magic ) { - set_touch_calibration(touch::default_calibration()); + if( data->touch_calibration_magic != TOUCH_CALIBRATION_MAGIC ) { + set_touch_calibration(touch::Calibration()); } return data->touch_calibration; } @@ -200,122 +515,116 @@ void set_serial_format(const serial_format_t new_value) { data->serial_format = new_value; } -/* static constexpr uint32_t playdead_magic = 0x88d3bb57; - -uint32_t playing_dead() { - return data->playing_dead; +bool show_gui_return_icon() { // add return icon in touchscreen menue + return data->ui_config.show_gui_return_icon(); } -void set_playing_dead(const uint32_t new_value) { - if( data->playdead_magic != playdead_magic ) { - set_playdead_sequence(0x8D1); // U D L R - } - data->playing_dead = new_value; +bool load_app_settings() { // load (last saved) app settings on startup of app + return data->ui_config.load_app_settings(); } -uint32_t playdead_sequence() { - if( data->playdead_magic != playdead_magic ) { - set_playdead_sequence(0x8D1); // U D L R - } - return data->playdead_sequence; -} - -void set_playdead_sequence(const uint32_t new_value) { - data->playdead_sequence = new_value; - data->playdead_magic = playdead_magic; -} */ - -// ui_config is an uint32_t var storing information bitwise -// bits 0,1,2 store the backlight timer -// bits 31, 30,29,28,27, 26, 25, 24 stores the different single bit configs depicted below -// bits on position 4 to 19 (16 bits) store the clkout frequency - -bool disable_touchscreen() { // Option to disable touch screen - return data->ui_config & (1 << 24); +bool save_app_settings() { // save app settings when closing app + return data->ui_config.save_app_settings(); } bool show_bigger_qr_code() { // show bigger QR code - return data->ui_config & (1 << 23); + return data->ui_config.show_bigger_qr_code(); +} + +bool disable_touchscreen() { // Option to disable touch screen + return data->ui_config.disable_touchscreen(); } bool hide_clock() { // clock hidden from main menu - return data->ui_config & (1 << 25); + return data->ui_config.hide_clock(); } bool clock_with_date() { // show clock with date, if not hidden - return data->ui_config & (1 << 26); + return data->ui_config.clock_with_date(); } bool clkout_enabled() { - return data->ui_config & (1 << 27); + return data->ui_config.clkout_enabled(); } bool config_speaker() { - return data->ui_config & (1 << 28); + return data->ui_config.config_speaker(); } + bool stealth_mode() { - return data->ui_config & (1 << 29); + return data->ui_config.stealth_mode(); } bool config_login() { - return data->ui_config & (1 << 30); + return data->ui_config.config_login(); } bool config_splash() { - return data->ui_config & (1 << 31); + return data->ui_config.config_splash(); } uint8_t config_cpld() { return data->hardware_config; } -uint32_t config_backlight_timer() { - const uint32_t timer_seconds[8] = { 0, 5, 15, 30, 60, 180, 300, 600 }; - return timer_seconds[data->ui_config & 7]; //first three bits, 8 possible values +backlight_config_t config_backlight_timer() { + return data->ui_config.config_backlight_timer(); +} + +void set_gui_return_icon(bool v) { + data->ui_config.set_gui_return_icon(v); +} + +void set_load_app_settings(bool v) { + data->ui_config.set_load_app_settings(v); +} + +void set_save_app_settings(bool v) { + data->ui_config.set_save_app_settings(v); +} + +void set_show_bigger_qr_code(bool v) { + data->ui_config.set_show_bigger_qr_code(v); } void set_disable_touchscreen(bool v) { - data->ui_config = (data->ui_config & ~(1 << 24)) | (v << 24); -} - -void set_show_bigger_qr_code(bool v) { - data->ui_config = (data->ui_config & ~(1 << 23)) | (v << 23); + data->ui_config.set_disable_touchscreen(v); } void set_clock_hidden(bool v) { - data->ui_config = (data->ui_config & ~(1 << 25)) | (v << 25); + data->ui_config.set_clock_hidden(v); } void set_clock_with_date(bool v) { - data->ui_config = (data->ui_config & ~(1 << 26)) | (v << 26); + data->ui_config.set_clock_with_date(v); } void set_clkout_enabled(bool v) { - data->ui_config = (data->ui_config & ~(1 << 27)) | (v << 27); + data->ui_config.set_clkout_enabled(v); } void set_config_speaker(bool v) { - data->ui_config = (data->ui_config & ~(1 << 28)) | (v << 28); + data->ui_config.set_config_speaker(v); } void set_stealth_mode(bool v) { - data->ui_config = (data->ui_config & ~(1 << 29)) | (v << 29); + data->ui_config.set_stealth_mode(v); } void set_config_login(bool v) { - data->ui_config = (data->ui_config & ~(1 << 30)) | (v << 30); + data->ui_config.set_config_login(v); } void set_config_splash(bool v) { - data->ui_config = (data->ui_config & ~(1 << 31)) | (v << 31); + data->ui_config.set_config_splash(v); } void set_config_cpld(uint8_t i) { data->hardware_config = i; } -void set_config_backlight_timer(uint32_t i) { - data->ui_config = (data->ui_config & ~7) | (i & 7); +void set_config_backlight_timer(const backlight_config_t& new_value) { + data->ui_config.set_config_backlight_timer(new_value); } /*void set_config_textentry(uint8_t new_value) { @@ -347,18 +656,11 @@ void set_pocsag_ignore_address(uint32_t address) { } uint32_t clkout_freq() { - uint16_t freq = (data->ui_config & 0x000FFFF0) >> 4; - if(freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) { - data->ui_config = (data->ui_config & ~0x000FFFF0) | clkout_freq_reset_value << 4; - return clkout_freq_reset_value; - } - else { - return freq; - } + return data->ui_config.clkout_freq(); } void set_clkout_freq(uint32_t freq) { - data->ui_config = (data->ui_config & ~0x000FFFF0) | (clkout_freq_range.clip(freq) << 4); + data->ui_config.set_clkout_freq(freq); } diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index bdfc1fef..f498bcae 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -25,6 +25,8 @@ #include +#include "optional.hpp" + #include "rf_path.hpp" #include "touch.hpp" #include "modems.hpp" @@ -36,6 +38,77 @@ using namespace serializer; namespace portapack { namespace persistent_memory { +enum backlight_timeout_t { + Timeout5Sec = 0, + Timeout15Sec = 1, + Timeout30Sec = 2, + Timeout60Sec = 3, + Timeout180Sec = 4, + Timeout300Sec = 5, + Timeout600Sec = 6, + Timeout3600Sec = 7, +}; + +struct backlight_config_t { +public: + backlight_config_t() : + _timeout_enum(backlight_timeout_t::Timeout600Sec), + _timeout_enabled(false) + { + } + + backlight_config_t( + backlight_timeout_t timeout_enum, + bool timeout_enabled + ) : + _timeout_enum(timeout_enum), + _timeout_enabled(timeout_enabled) + { + } + + bool timeout_enabled() const { + return _timeout_enabled; + } + + backlight_timeout_t timeout_enum() const { + return _timeout_enum; + } + + uint32_t timeout_seconds() const { + switch(timeout_enum()) { + case Timeout5Sec: return 5; + case Timeout15Sec: return 15; + case Timeout30Sec: return 30; + case Timeout60Sec: return 60; + case Timeout180Sec: return 180; + case Timeout300Sec: return 300; + default: + case Timeout600Sec: return 600; + case Timeout3600Sec: return 3600; + } + } + +private: + backlight_timeout_t _timeout_enum; + bool _timeout_enabled; +}; + +namespace cache { + +/* Set values in cache to sensible defaults. */ +void defaults(); + +/* Load cached settings from values in persistent RAM, replacing with defaults + * if persistent RAM contents appear to be invalid. */ +void init(); + +/* Calculate a check value for cached settings, and copy the check value and + * settings into persistent RAM. Intended to be called periodically to update + * persistent settings with current settings. */ +void persist(); + +} /* namespace cache */ + using ppb_t = int32_t; rf::Frequency tuned_frequency(); @@ -78,21 +151,27 @@ uint8_t config_cpld(); void set_config_cpld(uint8_t i); bool config_splash(); +bool show_gui_return_icon(); +bool load_app_settings(); +bool save_app_settings(); bool show_bigger_qr_code(); bool hide_clock(); bool clock_with_date(); bool config_login(); bool config_speaker(); -uint32_t config_backlight_timer(); +backlight_config_t config_backlight_timer(); bool disable_touchscreen(); -void set_config_splash(bool v); +void set_gui_return_icon(bool v); +void set_load_app_settings(bool v); +void set_save_app_settings(bool v); void set_show_bigger_qr_code(bool v); +void set_config_splash(bool v); void set_clock_hidden(bool v); void set_clock_with_date(bool v); void set_config_login(bool v); void set_config_speaker(bool v); -void set_config_backlight_timer(uint32_t i); +void set_config_backlight_timer(const backlight_config_t& new_value); void set_disable_touchscreen(bool v); //uint8_t ui_config_textentry(); diff --git a/firmware/common/utility.hpp b/firmware/common/utility.hpp index 60d25fe0..2cd3fcc6 100644 --- a/firmware/common/utility.hpp +++ b/firmware/common/utility.hpp @@ -95,27 +95,27 @@ struct range_t { const T minimum; const T maximum; - const T& clip(const T& value) const { + constexpr const T& clip(const T& value) const { return std::max(std::min(value, maximum), minimum); } - void reset_if_outside(T& value, const T& reset_value) const { + constexpr void reset_if_outside(T& value, const T& reset_value) const { if( (value < minimum ) || (value > maximum ) ) { value = reset_value; } } - bool below_range(const T& value) const { + constexpr bool below_range(const T& value) const { return value < minimum; } - bool contains(const T& value) const { + constexpr bool contains(const T& value) const { // TODO: Subtle gotcha here! Range test doesn't include maximum! return (value >= minimum) && (value < maximum); } - bool out_of_range(const T& value) const { + constexpr bool out_of_range(const T& value) const { // TODO: Subtle gotcha here! Range test in contains() doesn't include maximum! return !contains(value); } diff --git a/firmware/common/wm8731.hpp b/firmware/common/wm8731.hpp index ac164a04..a5c8908b 100644 --- a/firmware/common/wm8731.hpp +++ b/firmware/common/wm8731.hpp @@ -345,9 +345,8 @@ public: void speaker_disable() {}; - void microphone_enable(int8_t alc_mode) override { - (void)alc_mode; // to avoid "unused warning" when compiling. (@WM8731 we do not use that parameter) - // TODO: Implement, + void microphone_enable() override { + // TODO: Implement } void microphone_disable() override { diff --git a/firmware/tools/generate_world_map.bin.py b/firmware/tools/generate_world_map.bin.py index ffb28659..38f575e2 100755 --- a/firmware/tools/generate_world_map.bin.py +++ b/firmware/tools/generate_world_map.bin.py @@ -36,7 +36,7 @@ outfile.write(struct.pack('H', im.size[1])) print("Generating: \t" + outfile.name + "\n from\t\t" + im.filename + "\n please wait..."); for y in range (0, im.size[1]): - line = '' + line = b'' for x in range (0, im.size[0]): # RRRRRGGGGGGBBBBB pixel_lcd = (pix[x, y][0] >> 3) << 11 @@ -47,8 +47,8 @@ for y in range (0, im.size[1]): # pixel_lcd = (pix[x, y][0] >> 5) << 5 # pixel_lcd |= (pix[x, y][1] >> 5) << 2 # pixel_lcd |= (pix[x, y][2] >> 6) - line += str(struct.pack('H', pixel_lcd)) - outfile.write(line.encode('utf-8')) + line += struct.pack('H', pixel_lcd) + outfile.write(line) print(str(y) + '/' + str(im.size[1]) + '\r', end="") print("Ready."); diff --git a/flashing/driver/amd64/WdfCoInstaller01011.dll b/flashing/driver/amd64/WdfCoInstaller01011.dll new file mode 100644 index 00000000..d49d2913 Binary files /dev/null and b/flashing/driver/amd64/WdfCoInstaller01011.dll differ diff --git a/flashing/driver/amd64/winusbcoinstaller2.dll b/flashing/driver/amd64/winusbcoinstaller2.dll new file mode 100644 index 00000000..30e55025 Binary files /dev/null and b/flashing/driver/amd64/winusbcoinstaller2.dll differ diff --git a/flashing/msvcp120.dll b/flashing/msvcp120.dll new file mode 100644 index 00000000..4ea1efa7 Binary files /dev/null and b/flashing/msvcp120.dll differ diff --git a/flashing/msvcr120.dll b/flashing/msvcr120.dll new file mode 100644 index 00000000..d711c922 Binary files /dev/null and b/flashing/msvcr120.dll differ diff --git a/hackrf b/hackrf index e6eb4ba2..dfadf6a3 160000 --- a/hackrf +++ b/hackrf @@ -1 +1 @@ -Subproject commit e6eb4ba29bbe5dc2fcd092e394188bc10a8bad54 +Subproject commit dfadf6a31c5f5f9817f84f1d28c63243698f7299