Compare commits

...

26 Commits

Author SHA1 Message Date
Mark Thompson ba2407d691 Persistent audio mute support (#1161)
* Persistent speaker mute support #1100
* Moving persistent mute support from WM8731/AK4951 codec files to audio.cpp module for simplification
2023-06-17 23:15:21 +02:00
Kyle Reed 5743d3a3b9 Playlist cleanup (#1163)
* Functional rewrite of playlist
2023-06-17 22:01:46 +02:00
Kyle Reed 7f1c0f6f7e Explicitly set tx_model to make MicTX happy (#1162)
Co-authored-by: kallanreed <kallanreed@noreply.github.com>
2023-06-17 19:15:46 +02:00
Kyle Reed 650d299c99 Don't update radio directly when saving/restoring tx/rx model settings. (#1160)
* Set rf direction in RadioState

* centralize cpld load for TX->RX

* Remove calls to load_sram from all apps

* re-add CPLD hack, don't set radio values directly.

---------

Co-authored-by: kallanreed <kallanreed@noreply.github.com>
2023-06-17 07:54:52 -07:00
gullradriel 3a5c2da66c fixing bandwidth application, changed UI a bit (#1158)
* fixxing bandwidth application, moved 'continuous' from config page to main page in form of a 'loop' button. Removed looking glass button as it's not configurable to position on a range/signal
2023-06-16 07:50:04 +02:00
Kyle Reed d29826e6f2 Update playlist file parsing, reduce allocs (#1157)
* Update playlist file parsing, reduce allocs
* Cleanup, move impl to cpp
2023-06-15 22:15:26 +02:00
Kyle Reed 34fefd1cad Add file reader (#1155)
* Add file reader
* Add a simple test example of parsing settings.
* Use new FileLineReader to parse Glass presets
* Trim CRLF from Glass preset name
2023-06-15 09:45:13 +02:00
Mark Thompson a5c7eb2fbc Starting freq fixes when no App Settings, and support for App Settings in Scanner App (Mode/BW/Step only) (#1153)
* Fix initial freq when no App Settings tpms
* Default POCSAG freq when no App Settings
* Enable Scanner App Settings for Modulation/BW/Step
* Default SONDE freq when no App Settings
2023-06-14 16:54:19 +02:00
Kyle Reed 6298388fe1 Stash radio settings per app (#1151)
* add a little Stash utility.
* add radio state RAII helper.
* first part of radio_state changes
* add radio_state_ to rest of apps
* fix freq_step and format
* fix unused ui_sigfrx: corrected sample rate, added back freq setting
2023-06-14 09:57:20 +02:00
Kyle Reed 19491ce3f7 Add debug_log, fix tx_bht (#1149) 2023-06-13 08:14:26 +02:00
Kyle Reed 3db2053c21 Allows apps using app settings to use global frequency (#1148)
* Allow apps to not use persisted freq.
* use rx_freq for RX mode
* remove direct call to persistant_memory in tx_model
* app_setting defaults, and tx_view to use ctor value
2023-06-12 19:40:32 +02:00
gullradriel ccd7bd6fc2 Fixing txt_line_processing logic, adding back track number and plalist name (#1146) 2023-06-12 07:25:25 +02:00
Kyle Reed fff78ce00f Faster app_settings save (#1145)
* No-allocation settings save

* remove fixed TODO

---------

Co-authored-by: kallanreed <kallanreed@outlook.com>
2023-06-11 13:35:45 -07:00
Kyle Reed 8bd3d6249d App settings revamp (#1139)
* WIP AppSetting overhaul

* WIP migrating apps to new settings.

* remove settings, rename tuned => target

* formatting

* Minor fixes

* Fix hang on app load

* run formatter

* PR comment fixes

* Load modulation into receiver model in app_settings

* Run formatter

---------

Co-authored-by: kallanreed <kallanreed@outlook.com>
2023-06-11 11:47:13 -07:00
gullradriel f65e743c4c Recon revamp (#1144)
* fixing recon/scanner restarting while on pause and setting a manual start or end
* gui revamping, duplicated options suppressed from config menu
* recon_match_mode set at start
2023-06-11 18:49:28 +02:00
zxkmm 843880d22e playlist: fix track_number out of range and a little fix and alittle ui change (#1142)
* fix playlist track_number out of range
* implement pause
* fix for review: compatibility for old PPL grammar
2023-06-11 18:22:15 +02:00
gullradriel ec3cc7a859 Looking spectrum tune (#1143)
* finely tuned spectrum and marker precision, all modes

* hidding buttons when mode is not supported

* removing on show hide since widget implementation is buggy. Fine tuned values using signal generator to get around the corners

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2023-06-10 17:17:02 +02:00
Erwin Ried b1733cbd2a Merge pull request #1141 from u-foka/pmem-debug-rename
improve P.Memory naming consistency
2023-06-10 02:44:31 +02:00
Eisenberger Tamas 4ec2d64cb7 improve P.Memory naming consistency
I swear I wont touch these strings again :D
2023-06-10 00:34:27 +02:00
E.T d370dae170 increase touch sensitivity a little more (#1140)
and make the code a little more descriptive :)

Co-authored-by: Eisenberger Tamas <e.tamas@iwstudio.hu>
2023-06-09 23:45:26 +02:00
E.T 72f0a1be54 add dockerfile-nogit-arm (#1136)
works on aarc64 docker hosts

Co-authored-by: Eisenberger Tamas <e.tamas@iwstudio.hu>
2023-06-10 07:52:14 +12:00
E.T a2e5e03f07 Gcc12 related fixes (#1138)
* GCC12 related fixes but still compiles on GCC9

* Suppress warnings about volatile +=

* Enable c++20 if supported by the compiler

On gcc12 we need to use -std=c++20 since constexpr .c_str() on std::string is only officially available since c++20 and the new gcc wouldnt let us use it with older standard

* code format

---------

Co-authored-by: Eisenberger Tamas <e.tamas@iwstudio.hu>
2023-06-10 07:50:42 +12:00
E.T 47eda54d6a Format script (#1123)
* Add code formatting script

* dont forma the test framework

* use clang-format-13

---------

Co-authored-by: Eisenberger Tamas <e.tamas@iwstudio.hu>
2023-06-10 07:50:21 +12:00
gullradriel db81b9b1e1 code cleaning, fast and slow mode adjustement, dc pixels displayed (#1137)
* code cleaning, fast and slow mode adjustement, dc pixels displayed

* factorisation, comments

* adjusting offsets for alignement

* indent

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2023-06-09 17:13:44 +02:00
E.T b9de1918b4 fix pmem -> make backup_ram_t data members volatile (#1135)
* fix pmem -> make backup_ram_t data members volatile

plus add calculated crc to the pmem debug screen

* rename pmem debug menu to p.mem

As this is how its refered to in the wiki and other screens

* p.mem looked strange with capital P

---------

Co-authored-by: Eisenberger Tamas <e.tamas@iwstudio.hu>
2023-06-09 15:52:09 +02:00
dc2dc b87d26f271 Update HAM_70CM_BAND.TXT (#1134)
420-450 max Amateur Radio Band worldwide
2023-06-08 10:05:10 +02:00
158 changed files with 3056 additions and 2424 deletions
+41
View File
@@ -0,0 +1,41 @@
FROM ubuntu:xenial
# Set location to download ARM toolkit from.
# This will need to be changed over time or replaced with a static link to the latest release.
ENV ARMBINURL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-aarch64-linux.tar.bz2?revision=4583ce78-e7e7-459a-ad9f-bff8e94839f1&rev=4583ce78e7e7459aad9fbff8e94839f1&hash=C9B942D74CEA05FF9DE28380F267BB7D3F3B17A6 \
PATH=$HOME/bin:$PATH:/opt/build/armbin/bin
#Create volume /havoc/bin for compiled firmware binaries
VOLUME /havoc
WORKDIR /havoc/firmware
# Fetch dependencies from APT
RUN apt-get update && \
apt-get install -y git tar wget dfu-util cmake python3 ccache bzip2 liblz4-tool curl && \
apt-get -qy autoremove
#Install current pip from PyPa
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
python3 get-pip.py
#Fetch additional dependencies from Python 3.x pip
RUN pip install pyyaml
RUN ln -s /usr/bin/python3 /usr/bin/python && \
ln -s /usr/bin/pip3 /usr/bin/pip
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
# Grab the GNU ARM toolchain from arm.com
# Then extract contents to /opt/build/armbin/
RUN mkdir /opt/build && cd /opt/build && \
wget -O gcc-arm-none-eabi $ARMBINURL && \
mkdir armbin && \
tar --strip=1 -xjvf gcc-arm-none-eabi -C armbin
# Configure CCACHE
RUN mkdir ~/bin && cd ~/bin && \
for tool in gcc g++ cpp c++;do ln -s $(which ccache) arm-none-eabi-$tool;done
CMD cd .. && cd build && \
cmake .. && make firmware
+10 -1
View File
@@ -27,6 +27,8 @@
enable_language(C CXX ASM)
include(CheckCXXCompilerFlag)
project(application)
# Compiler options here.
@@ -36,7 +38,13 @@ set(USE_OPT "-Os -g --specs=nano.specs")
set(USE_COPT "-std=gnu99")
# C++ specific options here (added to USE_OPT).
set(USE_CPPOPT "-std=c++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
check_cxx_compiler_flag("-std=c++20" cpp20_supported)
if(cpp20_supported)
set(USE_CPPOPT "-std=c++20")
else()
set(USE_CPPOPT "-std=c++17")
endif()
set(USE_CPPOPT "${USE_CPPOPT} -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
# Enable this if you want the linker to remove unused code and data
set(USE_LINK_GC yes)
@@ -167,6 +175,7 @@ set(CPPSRC
#emu_cc1101.cpp
rfm69.cpp
event_m0.cpp
file_reader.cpp
file.cpp
freqman.cpp
io_file.cpp
+224 -75
View File
@@ -26,86 +26,235 @@
#include "file.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
#include "utility.hpp"
#include <algorithm>
#include <cstring>
#include <string_view>
namespace std {
namespace fs = std::filesystem;
using namespace portapack;
using namespace std::literals;
int app_settings::load(std::string application, AppSettings* settings) {
if (portapack::persistent_memory::load_app_settings()) {
file_path = folder + "/" + application + ".ini";
namespace app_settings {
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));
template <typename T>
static void read_setting(
std::string_view file_content,
std::string_view setting_name,
T& value) {
auto pos = file_content.find(setting_name);
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=");
settings->step = std::app_settings::read_long_long(file_content, "step=");
settings->modulation = std::app_settings::read_long_long(file_content, "modulation=");
settings->am_config_index = std::app_settings::read_long_long(file_content, "am_config_index=");
settings->nbfm_config_index = std::app_settings::read_long_long(file_content, "nbfm_config_index=");
settings->wfm_config_index = std::app_settings::read_long_long(file_content, "wfm_config_index=");
settings->squelch = std::app_settings::read_long_long(file_content, "squelch=");
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));
settings_file.write_line("step=" + to_string_dec_uint(settings->step));
settings_file.write_line("modulation=" + to_string_dec_uint(settings->modulation));
settings_file.write_line("am_config_index=" + to_string_dec_uint(settings->am_config_index));
settings_file.write_line("nbfm_config_index=" + to_string_dec_uint(settings->nbfm_config_index));
settings_file.write_line("wfm_config_index=" + to_string_dec_uint(settings->wfm_config_index));
settings_file.write_line("squelch=" + to_string_dec_uint(settings->squelch));
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);
if (pos != file_content.npos) {
pos += setting_name.length();
value = strtoll(&file_content[pos], nullptr, 10);
}
return (setting_value);
}
} /* namespace std */
template <typename T>
static void write_setting(File& file, std::string_view setting_name, const T& value) {
// NB: Not using file.write_line speed this up. This happens on every
// app exit when enabled so should be fast to keep the UX responsive.
StringFormatBuffer buffer;
size_t length = 0;
auto value_str = to_string_dec_uint(value, buffer, length);
file.write(setting_name.data(), setting_name.length());
file.write(value_str, length);
file.write("\r\n", 2);
}
static fs::path get_settings_path(const std::string& app_name) {
return fs::path{u"/SETTINGS"} / app_name + u".ini";
}
namespace setting {
constexpr std::string_view baseband_bandwidth = "baseband_bandwidth="sv;
constexpr std::string_view sampling_rate = "sampling_rate="sv;
constexpr std::string_view lna = "lna="sv;
constexpr std::string_view vga = "vga="sv;
constexpr std::string_view rx_amp = "rx_amp="sv;
constexpr std::string_view tx_amp = "tx_amp="sv;
constexpr std::string_view tx_gain = "tx_gain="sv;
constexpr std::string_view channel_bandwidth = "channel_bandwidth="sv;
constexpr std::string_view rx_frequency = "rx_frequency="sv;
constexpr std::string_view tx_frequency = "tx_frequency="sv;
constexpr std::string_view step = "step="sv;
constexpr std::string_view modulation = "modulation="sv;
constexpr std::string_view am_config_index = "am_config_index="sv;
constexpr std::string_view nbfm_config_index = "nbfm_config_index="sv;
constexpr std::string_view wfm_config_index = "wfm_config_index="sv;
constexpr std::string_view squelch = "squelch="sv;
constexpr std::string_view volume = "volume="sv;
} // namespace setting
// TODO: Only load/save values that are declared used.
// This will prevent switching apps from changing setting unnecessarily.
// TODO: Track which values are actually read.
// TODO: Maybe just use a dictionary which would allow for custom settings.
// TODO: Create a control value binding which will allow controls to
// be declaratively bound to a setting and persistence will be magic.
ResultCode load_settings(const std::string& app_name, AppSettings& settings) {
if (!portapack::persistent_memory::load_app_settings())
return ResultCode::SettingsDisabled;
auto file_path = get_settings_path(app_name);
auto data = File::read_file(file_path);
if (!data)
return ResultCode::LoadFailed;
if (flags_enabled(settings.mode, Mode::TX)) {
read_setting(*data, setting::tx_frequency, settings.tx_frequency);
read_setting(*data, setting::tx_amp, settings.tx_amp);
read_setting(*data, setting::tx_gain, settings.tx_gain);
read_setting(*data, setting::channel_bandwidth, settings.channel_bandwidth);
}
if (flags_enabled(settings.mode, Mode::RX)) {
read_setting(*data, setting::rx_frequency, settings.rx_frequency);
read_setting(*data, setting::rx_amp, settings.rx_amp);
read_setting(*data, setting::modulation, settings.modulation);
read_setting(*data, setting::am_config_index, settings.am_config_index);
read_setting(*data, setting::nbfm_config_index, settings.nbfm_config_index);
read_setting(*data, setting::wfm_config_index, settings.wfm_config_index);
read_setting(*data, setting::squelch, settings.squelch);
}
read_setting(*data, setting::baseband_bandwidth, settings.baseband_bandwidth);
read_setting(*data, setting::sampling_rate, settings.sampling_rate);
read_setting(*data, setting::lna, settings.lna);
read_setting(*data, setting::vga, settings.vga);
read_setting(*data, setting::step, settings.step);
read_setting(*data, setting::volume, settings.volume);
return ResultCode::Ok;
}
ResultCode save_settings(const std::string& app_name, AppSettings& settings) {
if (!portapack::persistent_memory::save_app_settings())
return ResultCode::SettingsDisabled;
File settings_file;
auto file_path = get_settings_path(app_name);
ensure_directory(file_path.parent_path());
auto error = settings_file.create(file_path);
if (error)
return ResultCode::SaveFailed;
if (flags_enabled(settings.mode, Mode::TX)) {
write_setting(settings_file, setting::tx_frequency, settings.tx_frequency);
write_setting(settings_file, setting::tx_amp, settings.tx_amp);
write_setting(settings_file, setting::tx_gain, settings.tx_gain);
write_setting(settings_file, setting::channel_bandwidth, settings.channel_bandwidth);
}
if (flags_enabled(settings.mode, Mode::RX)) {
write_setting(settings_file, setting::rx_frequency, settings.rx_frequency);
write_setting(settings_file, setting::rx_amp, settings.rx_amp);
write_setting(settings_file, setting::modulation, settings.modulation);
write_setting(settings_file, setting::am_config_index, settings.am_config_index);
write_setting(settings_file, setting::nbfm_config_index, settings.nbfm_config_index);
write_setting(settings_file, setting::wfm_config_index, settings.wfm_config_index);
write_setting(settings_file, setting::squelch, settings.squelch);
}
write_setting(settings_file, setting::baseband_bandwidth, settings.baseband_bandwidth);
write_setting(settings_file, setting::sampling_rate, settings.sampling_rate);
write_setting(settings_file, setting::lna, settings.lna);
write_setting(settings_file, setting::vga, settings.vga);
write_setting(settings_file, setting::step, settings.step);
write_setting(settings_file, setting::volume, settings.volume);
return ResultCode::Ok;
}
void copy_to_radio_model(const AppSettings& settings) {
// NB: Don't actually adjust the radio here or it will hang.
if (flags_enabled(settings.mode, Mode::TX)) {
if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency))
persistent_memory::set_target_frequency(settings.tx_frequency);
transmitter_model.configure_from_app_settings(settings);
}
if (flags_enabled(settings.mode, Mode::RX)) {
if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency))
persistent_memory::set_target_frequency(settings.rx_frequency);
receiver_model.configure_from_app_settings(settings);
receiver_model.set_configuration_without_update(
static_cast<ReceiverModel::Mode>(settings.modulation),
settings.step,
settings.am_config_index,
settings.nbfm_config_index,
settings.wfm_config_index,
settings.squelch);
}
receiver_model.set_frequency_step(settings.step);
receiver_model.set_normalized_headphone_volume(settings.volume);
}
void copy_from_radio_model(AppSettings& settings) {
if (flags_enabled(settings.mode, Mode::TX)) {
settings.tx_frequency = transmitter_model.target_frequency();
settings.baseband_bandwidth = transmitter_model.baseband_bandwidth();
settings.tx_amp = transmitter_model.rf_amp();
settings.tx_gain = transmitter_model.tx_gain();
settings.channel_bandwidth = transmitter_model.channel_bandwidth();
// TODO: Do these make sense for TX?
settings.sampling_rate = transmitter_model.sampling_rate();
settings.lna = transmitter_model.lna();
settings.vga = transmitter_model.vga();
}
if (flags_enabled(settings.mode, Mode::RX)) {
settings.rx_frequency = receiver_model.target_frequency();
settings.baseband_bandwidth = receiver_model.baseband_bandwidth();
settings.sampling_rate = receiver_model.sampling_rate();
settings.lna = receiver_model.lna();
settings.vga = receiver_model.vga();
settings.rx_amp = receiver_model.rf_amp();
settings.squelch = receiver_model.squelch_level();
settings.modulation = static_cast<uint8_t>(receiver_model.modulation());
settings.am_config_index = receiver_model.am_configuration();
settings.nbfm_config_index = receiver_model.nbfm_configuration();
settings.wfm_config_index = receiver_model.wfm_configuration();
}
settings.step = receiver_model.frequency_step();
settings.volume = receiver_model.normalized_headphone_volume();
}
/* SettingsManager *************************************************/
SettingsManager::SettingsManager(
std::string app_name,
Mode mode,
Options options)
: app_name_{std::move(app_name)},
settings_{},
loaded_{false} {
settings_.mode = mode;
settings_.options = options;
auto result = load_settings(app_name_, settings_);
if (result == ResultCode::Ok) {
loaded_ = true;
copy_to_radio_model(settings_);
}
}
SettingsManager::~SettingsManager() {
if (portapack::persistent_memory::save_app_settings()) {
copy_from_radio_model(settings_);
save_settings(app_name_, settings_);
}
}
} // namespace app_settings
+80 -37
View File
@@ -27,53 +27,96 @@
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include "file.hpp"
#include "max283x.hpp"
#include "string_format.hpp"
namespace std {
class app_settings {
namespace app_settings {
enum class ResultCode : uint8_t {
Ok, // settings found
LoadFailed, // settings (file) not found
SaveFailed, // unable to save settings
SettingsDisabled, // load/save disabled in settings
};
enum class Mode : uint8_t {
RX = 0x01,
TX = 0x02,
RX_TX = 0x03, // Both TX/RX
};
enum class Options {
None = 0x0000,
/* Don't use target frequency from app settings. */
UseGlobalTargetFrequency = 0x0001,
};
// TODO: separate types for TX/RX or union?
/* NB: See RX/TX model headers for default values. */
struct AppSettings {
Mode mode = Mode::RX;
Options options = Options::None;
uint32_t baseband_bandwidth = max283x::filter::bandwidth_minimum;
uint32_t sampling_rate = 3072000; // Good for 48k audio.
uint8_t lna = 32;
uint8_t vga = 32;
uint8_t rx_amp = 0;
uint8_t tx_amp = 0;
uint8_t tx_gain = 35;
uint32_t channel_bandwidth = 1;
uint32_t rx_frequency;
uint32_t tx_frequency;
uint32_t step = 25000;
uint8_t modulation = 1; // NFM
uint8_t am_config_index = 0;
uint8_t nbfm_config_index = 0;
uint8_t wfm_config_index = 0;
uint8_t squelch = 80;
uint8_t volume;
};
ResultCode load_settings(const std::string& app_name, AppSettings& settings);
ResultCode save_settings(const std::string& app_name, AppSettings& settings);
/* Copies common values to the receiver/transmitter models. */
void copy_to_radio_model(const AppSettings& settings);
/* Copies common values from the receiver/transmitter models. */
void copy_from_radio_model(AppSettings& settings);
/* RAII wrapper for automatically loading and saving settings for an app.
* NB: This should be added to a class before any LNA/VGA controls so that
* the receiver/transmitter models are set before the control ctors run. */
class SettingsManager {
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
SettingsManager(std::string app_name, Mode mode, Options options = Options::None);
~SettingsManager();
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;
uint32_t step;
uint8_t am_config_index;
uint8_t nbfm_config_index;
uint8_t wfm_config_index;
uint8_t squelch;
};
SettingsManager(const SettingsManager&) = delete;
SettingsManager& operator=(const SettingsManager&) = delete;
SettingsManager(SettingsManager&&) = delete;
SettingsManager& operator=(SettingsManager&&) = delete;
int load(std::string application, AppSettings* settings);
int save(std::string application, AppSettings* settings);
/* True if settings were successfully loaded from file. */
bool loaded() const { return loaded_; }
Mode mode() const { return settings_.mode; }
AppSettings& raw() { return settings_; }
private:
#define MAX_FILE_CONTENT_SIZE 1000
std::string app_name_;
AppSettings settings_;
bool loaded_;
};
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{};
} // namespace app_settings
long long int read_long_long(char* file_content, const char* setting_text);
}; // class app_settings
} // namespace std
ENABLE_FLAGS_OPERATORS(app_settings::Mode);
ENABLE_FLAGS_OPERATORS(app_settings::Options);
#endif /*__APP_SETTINGS_H__*/
+4 -22
View File
@@ -55,11 +55,6 @@ void ACARSLogger::log_raw_data(const acars::Packet& packet, const uint32_t frequ
namespace ui {
void ACARSAppView::update_freq(rf::Frequency f) {
set_target_frequency(f);
portapack::persistent_memory::set_tuned_frequency(f); // Maybe not ?
}
ACARSAppView::ACARSAppView(NavigationView& nav) {
baseband::run_image(portapack::spi_flash::image_tag_acars);
@@ -72,21 +67,17 @@ ACARSAppView::ACARSAppView(NavigationView& nav) {
&check_log,
&console});
receiver_model.set_sampling_rate(2457600);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.enable();
field_frequency.set_value(receiver_model.tuning_frequency());
update_freq(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
receiver_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -132,16 +123,7 @@ void ACARSAppView::on_packet(const acars::Packet& packet) {
// Log raw data whatever it contains
if (logger && logging)
logger->log_raw_data(packet, target_frequency());
}
void ACARSAppView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(new_value);
}
uint32_t ACARSAppView::target_frequency() const {
return target_frequency_;
logger->log_raw_data(packet, receiver_model.target_frequency());
}
} /* namespace ui */
+9 -8
View File
@@ -23,10 +23,11 @@
#ifndef __ACARS_APP_H__
#define __ACARS_APP_H__
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_widget.hpp"
#include "ui_receiver.hpp"
#include "ui_rssi.hpp"
#include "log_file.hpp"
#include "acars_packet.hpp"
@@ -56,6 +57,13 @@ class ACARSAppView : public View {
std::string title() const override { return "ACARS (WIP)"; };
private:
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_acars.hpp", app_settings::Mode::RX};
bool logging{false};
uint32_t packet_counter{0};
@@ -86,15 +94,8 @@ class ACARSAppView : public View {
std::unique_ptr<ACARSLogger> logger{};
uint32_t target_frequency_{};
void update_freq(rf::Frequency f);
void on_packet(const acars::Packet& packet);
uint32_t target_frequency() const;
void set_target_frequency(const uint32_t new_value);
MessageHandlerRegistration message_handler_packet{
Message::ID::ACARSPacket,
[this](Message* const p) {
+9 -41
View File
@@ -283,8 +283,8 @@ AISRecentEntryDetailView::AISRecentEntryDetailView(NavigationView& nav) {
});
button_done.on_select = [this](const ui::Button&) {
if (this->on_close) {
this->on_close();
if (on_close) {
on_close();
}
};
@@ -380,33 +380,23 @@ AISAppView::AISAppView(NavigationView& 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);
receiver_model.set_tuning_frequency(tuning_frequency());
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
if (!settings_.loaded())
receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable();
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
this->on_frequency_changed(v);
receiver_model.set_target_frequency(v);
};
options_channel.set_by_value(target_frequency());
options_channel.set_by_value(receiver_model.target_frequency());
recent_entries_view.on_select = [this](const AISRecentEntry& entry) {
this->on_show_detail(entry);
on_show_detail(entry);
};
recent_entry_detail_view.on_close = [this]() {
this->on_show_list();
on_show_list();
};
logger = std::make_unique<AISLogger>();
@@ -416,12 +406,7 @@ AISAppView::AISAppView(NavigationView& nav)
}
AISAppView::~AISAppView() {
// save app settings
app_settings.rx_frequency = target_frequency_;
settings.save("rx_ais", &app_settings);
receiver_model.disable();
baseband::shutdown();
}
@@ -465,21 +450,4 @@ void AISAppView::on_show_detail(const AISRecentEntry& entry) {
recent_entry_detail_view.focus();
}
void AISAppView::on_frequency_changed(const uint32_t new_target_frequency) {
set_target_frequency(new_target_frequency);
}
void AISAppView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(tuning_frequency());
}
uint32_t AISAppView::target_frequency() const {
return target_frequency_;
}
uint32_t AISAppView::tuning_frequency() const {
return target_frequency() - (sampling_rate / 4);
}
} /* namespace ui */
+7 -17
View File
@@ -34,6 +34,7 @@
#include "log_file.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ais_packet.hpp"
#include "lpc43xx_cpp.hpp"
@@ -154,9 +155,6 @@ class AISAppView : public View {
~AISAppView();
void set_parent_rect(const Rect new_parent_rect) override;
// Prevent painting of region covered entirely by a child.
// TODO: Add flag to View that specifies view does not need to be cleared before painting.
void paint(Painter&) override{};
void focus() override;
@@ -165,12 +163,13 @@ class AISAppView : public View {
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{};
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_ais", app_settings::Mode::RX};
NavigationView& nav_;
@@ -225,18 +224,9 @@ class AISAppView : public View {
}
}};
uint32_t target_frequency_ = initial_target_frequency;
void on_packet(const ais::Packet& packet);
void on_show_list();
void on_show_detail(const AISRecentEntry& entry);
void on_frequency_changed(const uint32_t new_target_frequency);
uint32_t target_frequency() const;
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};
} /* namespace ui */
+19 -36
View File
@@ -149,32 +149,19 @@ AnalogAudioView::AnalogAudioView(
&record_view,
&waterfall});
// Set on_change before initialising the field
field_frequency.on_change = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
};
// 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);
receiver_model.set_configuration_without_init(static_cast<ReceiverModel::Mode>(app_settings.modulation), app_settings.step, app_settings.am_config_index, app_settings.nbfm_config_index, app_settings.wfm_config_index, app_settings.squelch);
}
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.target_frequency());
field_frequency.on_change = [this](rf::Frequency f) {
receiver_model.set_target_frequency(f);
};
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
this->field_frequency.set_value(f);
field_frequency.set_value(f);
};
};
@@ -205,7 +192,7 @@ AnalogAudioView::AnalogAudioView(
};
waterfall.on_select = [this](int32_t offset) {
field_frequency.set_value(receiver_model.tuning_frequency() + offset);
field_frequency.set_value(receiver_model.target_frequency() + offset);
};
audio::output::start();
@@ -238,18 +225,18 @@ void AnalogAudioView::set_spec_trigger(uint16_t trigger) {
}
AnalogAudioView::~AnalogAudioView() {
// save app settings
app_settings.rx_frequency = field_frequency.value();
app_settings.lna = receiver_model.lna();
app_settings.vga = receiver_model.vga();
app_settings.rx_amp = receiver_model.rf_amp();
app_settings.step = receiver_model.frequency_step();
app_settings.modulation = (uint8_t)receiver_model.modulation();
app_settings.am_config_index = receiver_model.am_configuration();
app_settings.nbfm_config_index = receiver_model.nbfm_configuration();
app_settings.wfm_config_index = receiver_model.wfm_configuration();
app_settings.squelch = receiver_model.squelch_level();
settings.save("rx_audio", &app_settings);
// // save app settings
// app_settings.rx_frequency = field_frequency.value();
// app_settings.lna = receiver_model.lna();
// app_settings.vga = receiver_model.vga();
// app_settings.rx_amp = receiver_model.rf_amp();
// app_settings.step = receiver_model.frequency_step();
// app_settings.modulation = (uint8_t)receiver_model.modulation();
// app_settings.am_config_index = receiver_model.am_configuration();
// app_settings.nbfm_config_index = receiver_model.nbfm_configuration();
// app_settings.wfm_config_index = receiver_model.wfm_configuration();
// app_settings.squelch = receiver_model.squelch_level();
// settings.save("rx_audio", &app_settings);
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
// both?
@@ -279,10 +266,6 @@ void AnalogAudioView::focus() {
field_frequency.focus();
}
void AnalogAudioView::on_tuning_frequency_changed(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
}
void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
receiver_model.set_baseband_bandwidth(bandwidth_hz);
}
@@ -30,6 +30,7 @@
#include "ui_record_view.hpp"
#include "ui_styles.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "tone_key.hpp"
namespace ui {
@@ -155,9 +156,10 @@ class AnalogAudioView : public View {
private:
static constexpr ui::Dim header_height = 3 * 16;
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_audio", app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency};
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};
@@ -220,7 +222,6 @@ class AnalogAudioView : public View {
spectrum::WaterfallWidget waterfall{true};
void on_tuning_frequency_changed(rf::Frequency f);
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
void on_modulation_changed(const ReceiverModel::Mode modulation);
void on_show_options_frequency();
+7 -22
View File
@@ -58,25 +58,16 @@ AnalogTvView::AnalogTvView(
// Set on_change before initialising the field
field_frequency.on_change = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
this->on_target_frequency_changed(f);
};
// 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_value(receiver_model.target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
this->on_target_frequency_changed(f);
this->field_frequency.set_value(f);
};
};
@@ -103,7 +94,7 @@ AnalogTvView::AnalogTvView(
};
tv.on_select = [this](int32_t offset) {
field_frequency.set_value(receiver_model.tuning_frequency() + offset);
field_frequency.set_value(receiver_model.target_frequency() + offset);
};
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
@@ -111,12 +102,6 @@ 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();
@@ -140,8 +125,8 @@ void AnalogTvView::focus() {
field_frequency.focus();
}
void AnalogTvView::on_tuning_frequency_changed(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
void AnalogTvView::on_target_frequency_changed(rf::Frequency f) {
receiver_model.set_target_frequency(f);
}
void AnalogTvView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
+5 -4
View File
@@ -31,6 +31,7 @@
#include "ui_record_view.hpp"
#include "ui_styles.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "tone_key.hpp"
@@ -52,9 +53,9 @@ class AnalogTvView : public View {
private:
static constexpr ui::Dim header_height = 3 * 16;
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_tv", app_settings::Mode::RX};
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};
@@ -99,7 +100,7 @@ class AnalogTvView : public View {
tv::TVWidget tv{};
void on_tuning_frequency_changed(rf::Frequency f);
void on_target_frequency_changed(rf::Frequency f);
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
void on_modulation_changed(const ReceiverModel::Mode modulation);
void on_show_options_frequency();
+18 -39
View File
@@ -21,10 +21,9 @@
*/
#include "capture_app.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
namespace ui {
@@ -46,22 +45,15 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
&waterfall,
});
// Hack for initialization
// TODO: This should be included in a more global section so apps dont need to do it
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
//-------------------
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
receiver_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_tuning_frequency_changed(f);
this->field_frequency.set_value(f);
};
};
@@ -74,15 +66,12 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
option_bandwidth.on_change = [this](size_t, uint32_t base_rate) {
sampling_rate = 8 * base_rate; // Decimation by 8 done on baseband side
/* base_rate is used for FFT calculation and display LCD, and also in recording writing SD Card rate. */
/* ex. sampling_rate values, 4Mhz, when recording 500 kHz (BW) and fs 8 Mhz , when selected 1 Mhz BW ...*/
/* ex. recording 500kHz BW to .C16 file, base_rate clock 500kHz x2(I,Q) x 2 bytes (int signed) =2MB/sec rate SD Card */
/* base_rate is used for FFT calculation and display LCD, and also in recording writing SD Card rate. */
/* ex. sampling_rate values, 4Mhz, when recording 500 kHz (BW) and fs 8 Mhz, when selected 1 Mhz BW ... */
/* ex. recording 500kHz BW to .C16 file, base_rate clock 500kHz x2(I,Q) x 2 bytes (int signed) =2MB/sec rate SD Card */
waterfall.on_hide();
record_view.set_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
/* Set up proper anti aliasing BPF bandwith in MAX2837 before ADC sampling according to the new added BW Options . */
/* Set up proper anti aliasing BPF bandwith in MAX2837 before ADC sampling according to the new added BW Options . */
switch (sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
@@ -99,30 +88,33 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
break;
case 14000000: // BW capture 1,75Mhz , fs = 8 x 1,75Mhz = 14Mhz
// good BPF ,good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 5000000;
break;
case 16000000: // BW capture 2Mhz , fs = 8 x 2Mhz = 16Mhz
// good BPF ,good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 6000000;
break;
case 20000000: // BW capture 2,5Mhz , fs= 8 x 2,5 Mhz = 20Mhz
// good BPF ,good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 7000000;
break;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor , better 8Mhz
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor, better 8Mhz
anti_alias_baseband_bandwidth_filter = 8000000;
}
record_view.set_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter);
waterfall.on_show();
};
option_bandwidth.set_selected_index(7); // 500k, Preselected starting default option 500kHz
option_bandwidth.set_selected_index(7); // Preselected default option 500kHz.
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
receiver_model.enable();
@@ -133,20 +125,11 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
}
CaptureAppView::~CaptureAppView() {
// Hack for preventing halting other apps
// TODO: This should be also part of something global
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
// ----------------------------
receiver_model.disable();
baseband::shutdown();
}
void CaptureAppView::on_hide() {
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
// it's being shown or hidden.
waterfall.on_hide();
View::on_hide();
}
@@ -154,7 +137,7 @@ void CaptureAppView::on_hide() {
void CaptureAppView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
const ui::Rect waterfall_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height};
ui::Rect waterfall_rect{0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height};
waterfall.set_parent_rect(waterfall_rect);
}
@@ -162,8 +145,4 @@ void CaptureAppView::focus() {
record_view.focus();
}
void CaptureAppView::on_tuning_frequency_changed(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
}
} /* namespace ui */
+27 -22
View File
@@ -28,23 +28,25 @@
#include "ui_receiver.hpp"
#include "ui_record_view.hpp"
#include "ui_spectrum.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#define BW_OPTIONS \
{" 8k5", 8500}, \
{" 11k", 11000}, \
{" 16k", 16000}, \
{" 25k", 25000}, \
{" 50k", 50000}, \
{" 100k", 100000}, \
{" 250k", 250000}, \
{" 500k", 500000}, /* Previous Limit bandwith Option with perfect micro SD write .C16 format operaton.*/ \
{" 600k", 600000}, /* That extended option is still possible to record with FW version Mayhem v1.41 (< 2,5MB/sec) */ \
{" 750k", 750000}, /* From that BW onwards, the LCD is ok, but the recorded file is auto decimated,(not real file size) */ \
{"1100k", 1100000}, \
{"1750k", 1750000}, \
{"2000k", 2000000}, \
{"2500k", 2500000}, \
{"2750k", 2750000}, // That is our max Capture option , to keep using later / 8 decimation (22Mhz sampling ADC)
#define BW_OPTIONS \
{" 8k5", 8500}, \
{" 11k", 11000}, \
{" 16k", 16000}, \
{" 25k", 25000}, \
{" 50k", 50000}, \
{" 100k", 100000}, \
{" 250k", 250000}, \
{" 500k", 500000}, /* Previous Limit bandwith Option with perfect micro SD write .C16 format operaton.*/ \
{" 600k", 600000}, /* That extended option is still possible to record with FW version Mayhem v1.41 (< 2,5MB/sec) */ \
{" 750k", 750000}, /* From this BW onwards, the LCD is ok, but the recorded file is decimated, (not real file size) */ \
{"1100k", 1100000}, \
{"1750k", 1750000}, \
{"2000k", 2000000}, \
{"2500k", 2500000}, \
{"2750k", 2750000}, // That is our max Capture option, to keep using later / 8 decimation (22Mhz sampling ADC)
namespace ui {
@@ -54,20 +56,23 @@ class CaptureAppView : public View {
~CaptureAppView();
void on_hide() override;
void set_parent_rect(const Rect new_parent_rect) override;
void focus() override;
void set_parent_rect(const Rect new_parent_rect) override;
std::string title() const override { return "Capture"; };
private:
static constexpr ui::Dim header_height = 3 * 16;
uint32_t sampling_rate = 0;
uint32_t anti_alias_baseband_bandwidth_filter = 2500000; // we rename the previous var , and change type static constexpr to normal var.
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_capture", app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency};
void on_tuning_frequency_changed(rf::Frequency f);
uint32_t sampling_rate = 0;
uint32_t anti_alias_baseband_bandwidth_filter = 2500000;
void on_target_frequency_changed(rf::Frequency f);
Labels labels{
{{0 * 8, 1 * 16}, "Rate:", Color::light_grey()},
+2 -14
View File
@@ -110,17 +110,9 @@ 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);
}
if (!settings_.loaded())
receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.set_tuning_frequency(initial_target_frequency);
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
receiver_model.enable();
logger = std::make_unique<ERTLogger>();
@@ -130,11 +122,7 @@ ERTAppView::ERTAppView(NavigationView&) {
}
ERTAppView::~ERTAppView() {
// save app settings
settings.save("rx_ert", &app_settings);
receiver_model.disable();
baseband::shutdown();
}
+9 -7
View File
@@ -29,6 +29,7 @@
#include "event_m0.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "log_file.hpp"
#include "ert_packet.hpp"
@@ -108,10 +109,6 @@ using ERTRecentEntriesView = RecentEntriesView<ERTRecentEntries>;
class ERTAppView : public View {
public:
static constexpr uint32_t initial_target_frequency = 911600000;
static constexpr uint32_t sampling_rate = 4194304;
static constexpr uint32_t baseband_bandwidth = 2500000;
ERTAppView(NavigationView& nav);
~ERTAppView();
@@ -126,12 +123,17 @@ class ERTAppView : public View {
std::string title() const override { return "ERT RX"; };
private:
static constexpr uint32_t initial_target_frequency = 911600000;
ERTRecentEntries recent{};
std::unique_ptr<ERTLogger> logger{};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{
2500000 /* bandwidth */,
4194304 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_ert", app_settings::Mode::RX};
const RecentEntriesColumns columns{{
{"ID", 10},
+8 -27
View File
@@ -26,10 +26,10 @@
#include "ui_fileman.hpp"
#include "io_file.hpp"
#include "utility.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
#include "cpld_update.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
@@ -81,7 +81,7 @@ void GpsSimAppView::on_file_changed(std::filesystem::path new_file_path) {
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 1) + "Hz");
auto file_size = data_file.size();
auto duration = (file_size * 1000) / (1 * 2 * sample_rate);
auto duration = ms_duration(file_size, sample_rate, 2);
progressbar.set_max(file_size / 1024);
text_filename.set(file_path.filename().string().substr(0, 12));
@@ -129,7 +129,6 @@ void GpsSimAppView::start() {
if (reader) {
button_play.set_bitmap(&bitmap_stop);
baseband::set_sample_rate(sample_rate);
replay_thread = std::make_unique<ReplayThread>(
std::move(reader),
@@ -142,7 +141,6 @@ void GpsSimAppView::start() {
}
transmitter_model.set_sampling_rate(sample_rate);
transmitter_model.set_baseband_bandwidth(baseband_bandwidth);
transmitter_model.enable();
}
@@ -183,28 +181,25 @@ GpsSimAppView::GpsSimAppView(
&text_duration,
&progressbar,
&field_frequency,
&tx_view, // now it handles previous rfgain , rfamp.
&tx_view, // now it handles previous rfgain, rfamp.
&check_loop,
&button_play,
&waterfall,
});
field_frequency.set_value(target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.set_value(transmitter_model.target_frequency());
field_frequency.set_step(5000);
field_frequency.on_change = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
transmitter_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
this->field_frequency.set_value(f);
};
};
field_frequency.set_step(5000);
button_play.on_select = [this](ImageButton&) {
this->toggle();
};
@@ -219,8 +214,7 @@ GpsSimAppView::GpsSimAppView(
GpsSimAppView::~GpsSimAppView() {
transmitter_model.disable();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void GpsSimAppView::on_hide() {
@@ -239,17 +233,4 @@ void GpsSimAppView::set_parent_rect(const Rect new_parent_rect) {
waterfall.set_parent_rect(waterfall_rect);
}
void GpsSimAppView::on_target_frequency_changed(rf::Frequency f) {
set_target_frequency(f);
}
void GpsSimAppView::set_target_frequency(const rf::Frequency new_value) {
persistent_memory::set_tuned_frequency(new_value);
;
}
rf::Frequency GpsSimAppView::target_frequency() const {
return persistent_memory::tuned_frequency();
}
} /* namespace ui */
+9 -5
View File
@@ -27,15 +27,17 @@
#define SHORT_UI true
#define NORMAL_UI false
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "replay_thread.hpp"
#include "ui_spectrum.hpp"
#include "ui_transmitter.hpp"
#include <string>
#include <memory>
#include "ui_transmitter.hpp"
namespace ui {
@@ -52,6 +54,12 @@ class GpsSimAppView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
3000000 /* bandwidth */,
500000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_gps", app_settings::Mode::TX};
static constexpr ui::Dim header_height = 3 * 16;
@@ -63,12 +71,8 @@ class GpsSimAppView : public View {
const size_t buffer_count{3};
void on_file_changed(std::filesystem::path new_file_path);
void on_target_frequency_changed(rf::Frequency f);
void on_tx_progress(const uint32_t progress);
void set_target_frequency(const rf::Frequency new_value);
rf::Frequency target_frequency() const;
void toggle();
void start();
void stop(const bool do_loop);
+5 -21
View File
@@ -27,7 +27,6 @@
#include "lge_app.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "ui_textentry.hpp"
#include "string_format.hpp"
@@ -44,13 +43,8 @@ void LGEView::focus() {
}
LGEView::~LGEView() {
// save app settings
app_settings.tx_frequency = transmitter_model.tuning_frequency();
settings.save("tx_lge", &app_settings);
transmitter_model.disable();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void LGEView::generate_lge_frame(const uint8_t command, const uint16_t address_a, const uint16_t address_b, std::vector<uint8_t>& data) {
@@ -243,12 +237,11 @@ void LGEView::generate_frame_collier() {
void LGEView::start_tx() {
if (tx_mode == ALL) {
transmitter_model.set_tuning_frequency(channels[channel_index]);
transmitter_model.set_target_frequency(channels[channel_index]);
tx_view.on_show(); // Refresh tuning frequency display
tx_view.set_dirty();
}
transmitter_model.set_sampling_rate(2280000);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
chThdSleep(100);
@@ -306,15 +299,6 @@ LGEView::LGEView(NavigationView& nav) {
&console,
&tx_view});
// 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);
@@ -333,9 +317,9 @@ LGEView::LGEView(NavigationView& nav) {
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -30,6 +30,7 @@
#include "transmitter_model.hpp"
#include "portapack.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -49,9 +50,12 @@ class LGEView : public View {
ALL
};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_lge", app_settings::Mode::TX};
tx_modes tx_mode = IDLE;
+12 -42
View File
@@ -51,11 +51,6 @@ void POCSAGLogger::log_decoded(
namespace ui {
void POCSAGAppView::update_freq(rf::Frequency f) {
set_target_frequency(f);
portapack::persistent_memory::set_tuned_frequency(f); // Maybe not ?
}
POCSAGAppView::POCSAGAppView(NavigationView& nav) {
uint32_t ignore_address;
@@ -74,36 +69,21 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
&sym_ignore,
&console});
// Set on_change before initialising the field
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
// load app settings TODO: needed?
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_lna.set_value(receiver_model.lna());
field_vga.set_value(receiver_model.vga());
field_rf_amp.set_value(receiver_model.rf_amp());
field_frequency.set_value(receiver_model.tuning_frequency());
}
if (!settings_.loaded())
receiver_model.set_target_frequency(initial_target_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.target_frequency());
field_frequency.on_change = [this](rf::Frequency f) {
receiver_model.set_target_frequency(f);
};
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -122,16 +102,15 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
logger->append(LOG_ROOT_DIR "/POCSAG.TXT");
audio::output::start();
audio::output::unmute();
baseband::set_pocsag();
}
POCSAGAppView::~POCSAGAppView() {
// save app settings
app_settings.rx_frequency = field_frequency.value();
settings.save("rx_pocsag", &app_settings);
void POCSAGAppView::focus() {
check_log.focus();
}
POCSAGAppView::~POCSAGAppView() {
audio::output::stop();
// Save ignored address
@@ -205,16 +184,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) {
// TODO: make setting.
// Log raw data whatever it contains
if (logger && logging())
logger->log_raw_data(message->packet, target_frequency());
}
void POCSAGAppView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(new_value);
}
uint32_t POCSAGAppView::target_frequency() const {
return target_frequency_;
logger->log_raw_data(message->packet, receiver_model.target_frequency());
}
} /* namespace ui */
+5 -11
View File
@@ -29,6 +29,7 @@
#include "log_file.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "pocsag.hpp"
#include "pocsag_packet.hpp"
@@ -53,16 +54,16 @@ class POCSAGAppView : public View {
~POCSAGAppView();
std::string title() const override { return "POCSAG RX"; };
void focus() override;
private:
static constexpr uint32_t initial_target_frequency = 466175000;
bool logging() const { return check_log.value(); };
bool ignore() const { return check_ignore.value(); };
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_pocsag", app_settings::Mode::RX};
uint32_t last_address = 0xFFFFFFFF;
pocsag::POCSAGState pocsag_state{};
@@ -111,15 +112,8 @@ class POCSAGAppView : public View {
std::unique_ptr<POCSAGLogger> logger{};
uint32_t target_frequency_ = initial_target_frequency;
void update_freq(rf::Frequency f);
void on_packet(const POCSAGPacketMessage* message);
uint32_t target_frequency() const;
void set_target_frequency(const uint32_t new_value);
MessageHandlerRegistration message_handler_packet{
Message::ID::POCSAGPacket,
[this](Message* const p) {
+7 -23
View File
@@ -26,10 +26,10 @@
#include "ui_fileman.hpp"
#include "io_file.hpp"
#include "cpld_update.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include "utility.hpp"
using namespace portapack;
@@ -80,7 +80,7 @@ void ReplayAppView::on_file_changed(std::filesystem::path new_file_path) {
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
auto file_size = data_file.size();
auto duration = (file_size * 1000) / (2 * 2 * sample_rate);
auto duration = ms_duration(file_size, sample_rate, 4);
progressbar.set_max(file_size);
text_filename.set(file_path.filename().string().substr(0, 12));
@@ -194,17 +194,16 @@ ReplayAppView::ReplayAppView(
&waterfall,
});
field_frequency.set_value(target_frequency());
field_frequency.set_value(transmitter_model.target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
transmitter_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
this->field_frequency.set_value(f);
field_frequency.set_value(f);
};
};
@@ -227,9 +226,7 @@ ReplayAppView::~ReplayAppView() {
display.fill_rectangle({0, 0, 240, 320}, Color::black()); // Solving sometimes visible bottom waterfall artifacts, clearing all LCD pixels.
chThdSleepMilliseconds(40); // (that happened sometimes if we interrupt the waterfall play at the beggining of the play around 25% and exit )
hackrf::cpld::load_sram_no_verify(); // to leave all RX reception ok, without "ghost interference signal problem" at the exit .
baseband::shutdown(); // better this function at the end, after load_sram(). If not , sometimes produced hang up (now not , it is ok).
baseband::shutdown();
}
void ReplayAppView::on_hide() {
@@ -247,17 +244,4 @@ void ReplayAppView::set_parent_rect(const Rect new_parent_rect) {
waterfall.set_parent_rect(waterfall_rect);
}
void ReplayAppView::on_target_frequency_changed(rf::Frequency f) {
set_target_frequency(f);
}
void ReplayAppView::set_target_frequency(const rf::Frequency new_value) {
persistent_memory::set_tuned_frequency(new_value);
;
}
rf::Frequency ReplayAppView::target_frequency() const {
return persistent_memory::tuned_frequency();
}
} /* namespace ui */
+6 -5
View File
@@ -26,15 +26,17 @@
#define SHORT_UI true
#define NORMAL_UI false
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "replay_thread.hpp"
#include "ui_spectrum.hpp"
#include "ui_transmitter.hpp"
#include <string>
#include <memory>
#include "ui_transmitter.hpp"
namespace ui {
@@ -51,6 +53,9 @@ class ReplayAppView : public View {
private:
NavigationView& nav_;
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_replay", app_settings::Mode::TX};
static constexpr ui::Dim header_height = 3 * 16;
@@ -62,12 +67,8 @@ class ReplayAppView : public View {
const size_t buffer_count{3};
void on_file_changed(std::filesystem::path new_file_path);
void on_target_frequency_changed(rf::Frequency f);
void on_tx_progress(const uint32_t progress);
void set_target_frequency(const rf::Frequency new_value);
rf::Frequency target_frequency() const;
void toggle();
void start();
void stop(const bool do_loop);
+4 -20
View File
@@ -25,7 +25,6 @@
#include "soundboard_app.hpp"
#include "string_format.hpp"
#include "tonesets.hpp"
#include "cpld_update.hpp"
using namespace tonekey;
using namespace portapack;
@@ -106,6 +105,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
EventDispatcher::send_message(message);
});
// TODO: Delete all this and use tx model.
baseband::set_audiotx_config(
1536000 / 20, // Update vu-meter at 20Hz
transmitter_model.channel_bandwidth(),
@@ -119,8 +119,6 @@ void SoundBoardView::start_tx(const uint32_t id) {
);
baseband::set_sample_rate(sample_rate);
transmitter_model.set_sampling_rate(1536000);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
tx_view.set_transmitting(true);
@@ -235,15 +233,6 @@ 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();
button_next_page.on_select = [this](Button&) {
@@ -266,9 +255,9 @@ SoundBoardView::SoundBoardView(
check_random.set_value(false);
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
@@ -283,14 +272,9 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
} // namespace ui
+8 -4
View File
@@ -31,6 +31,7 @@
#include "io_wave.hpp"
#include "tone_key.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -49,11 +50,14 @@ class SoundBoardView : public View {
std::string title() const override { return "Soundbrd TX"; };
private:
NavigationView& nav_;
TxRadioState radio_state_{
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_soundboard", app_settings::Mode::TX};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
NavigationView& nav_;
enum tx_modes {
NORMAL = 0,
+7 -38
View File
@@ -78,9 +78,9 @@ void TPMSLogger::on_packet(const tpms::Packet& packet, const uint32_t target_fre
const auto hex_formatted = packet.symbols_formatted();
// TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue!
const auto tuning_frequency_str = to_string_dec_uint(target_frequency, 10);
const auto target_frequency_str = to_string_dec_uint(target_frequency, 10);
std::string entry = tuning_frequency_str + " " + tpms::format::signal_type(packet.signal_type()) + " " + hex_formatted.data + "/" + hex_formatted.errors;
std::string entry = target_frequency_str + " " + tpms::format::signal_type(packet.signal_type()) + " " + hex_formatted.data + "/" + hex_formatted.errors;
log_file.write_entry(packet.received_at(), entry);
}
@@ -157,25 +157,15 @@ TPMSAppView::TPMSAppView(NavigationView&) {
&field_vga,
&recent_entries_view});
// 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());
if (!settings_.loaded())
receiver_model.set_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();
options_band.on_change = [this](size_t, OptionsField::value_t v) {
this->on_band_changed(v);
receiver_model.set_target_frequency(v);
};
options_band.set_by_value(target_frequency());
options_band.set_by_value(receiver_model.target_frequency());
options_pressure.on_change = [this](size_t, int32_t i) {
tpms::format::use_kpa = !i;
@@ -198,10 +188,6 @@ TPMSAppView::TPMSAppView(NavigationView&) {
}
TPMSAppView::~TPMSAppView() {
// save app settings
app_settings.rx_frequency = target_frequency_;
settings.save("rx_tpms", &app_settings);
receiver_model.disable();
baseband::shutdown();
}
@@ -224,7 +210,7 @@ void TPMSAppView::set_parent_rect(const Rect new_parent_rect) {
void TPMSAppView::on_packet(const tpms::Packet& packet) {
if (logger) {
logger->on_packet(packet, target_frequency());
logger->on_packet(packet, receiver_model.target_frequency());
}
const auto reading_opt = packet.reading();
@@ -241,21 +227,4 @@ void TPMSAppView::on_show_list() {
recent_entries_view.focus();
}
void TPMSAppView::on_band_changed(const uint32_t new_band_frequency) {
set_target_frequency(new_band_frequency);
}
void TPMSAppView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(tuning_frequency());
}
uint32_t TPMSAppView::target_frequency() const {
return target_frequency_;
}
uint32_t TPMSAppView::tuning_frequency() const {
return target_frequency() - (sampling_rate / 4);
}
} /* namespace ui */
+7 -18
View File
@@ -28,6 +28,7 @@
#include "ui_rssi.hpp"
#include "ui_channel.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "event_m0.hpp"
#include "log_file.hpp"
@@ -38,10 +39,6 @@
namespace std {
constexpr bool operator==(const tpms::TransponderID& lhs, const tpms::TransponderID& rhs) {
return (lhs.value() == rhs.value());
}
} /* namespace std */
struct TPMSRecentEntry {
@@ -106,12 +103,13 @@ class TPMSAppView : public View {
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{};
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_tpms", app_settings::Mode::RX};
MessageHandlerRegistration message_handler_packet{
Message::ID::TPMSPacket,
@@ -175,18 +173,9 @@ class TPMSAppView : public View {
}};
TPMSRecentEntriesView recent_entries_view{columns, recent};
uint32_t target_frequency_ = initial_target_frequency;
void on_packet(const tpms::Packet& packet);
void on_show_list();
void update_view();
void on_band_changed(const uint32_t new_band_frequency);
uint32_t target_frequency() const;
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};
} /* namespace ui */
+1 -2
View File
@@ -47,7 +47,7 @@ using namespace portapack;
namespace ui {
void AboutView::on_show() {
transmitter_model.set_tuning_frequency(1337000000); // TODO: Change
transmitter_model.set_target_frequency(1337000000); // TODO: Change
transmitter_model.set_baseband_configuration({
.mode = 0,
.sampling_rate = 1536000,
@@ -56,7 +56,6 @@ void AboutView::on_show() {
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
transmitter_model.set_vga(40);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_audiotx_data(32, 50, false, 0);
+1 -23
View File
@@ -288,13 +288,6 @@ void ADSBRxView::focus() {
}
ADSBRxView::~ADSBRxView() {
receiver_model.set_tuning_frequency(prevFreq); // Restore previous frequency on exit
// 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();
@@ -502,17 +495,6 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
&rssi,
&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();
@@ -528,14 +510,10 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
on_tick_second();
};
prevFreq = receiver_model.tuning_frequency(); // Store previous frequency on creation
baseband::set_adsb();
receiver_model.set_tuning_frequency(1090000000);
receiver_model.set_target_frequency(1090000000);
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_sampling_rate(2000000);
receiver_model.set_baseband_bandwidth(2500000);
receiver_model.enable();
}
+8 -4
View File
@@ -33,6 +33,7 @@
#include "adsb.hpp"
#include "message.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "crc.hpp"
using namespace adsb;
@@ -340,7 +341,13 @@ class ADSBRxView : public View {
void sort_entries_by_state();
private:
rf::Frequency prevFreq = {0};
RxRadioState radio_state_{
2500000 /* bandwidth */,
2000000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_adsb", app_settings::Mode::RX};
std::unique_ptr<ADSBLogger> logger{};
void on_frame(const ADSBFrameMessage* message);
void on_tick_second();
@@ -350,9 +357,6 @@ class ADSBRxView : public View {
#define MARKER_UPDATE_SECONDS (5)
int ticksSinceMarkerRefresh{MARKER_UPDATE_SECONDS - 1};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
const RecentEntriesColumns columns{{{"ICAO/Call", 9},
{"Lvl", 3},
+3 -19
View File
@@ -26,7 +26,6 @@
#include "manchester.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
#include "cpld_update.hpp"
#include "baseband_api.hpp"
#include <cstring>
@@ -273,13 +272,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, withouth ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void ADSBTxView::generate_frames() {
@@ -303,8 +297,6 @@ void ADSBTxView::generate_frames() {
void ADSBTxView::start_tx() {
generate_frames();
transmitter_model.set_sampling_rate(4000000U);
transmitter_model.set_baseband_bandwidth(10000000);
transmitter_model.enable();
baseband::set_adsb();
@@ -327,18 +319,10 @@ ADSBTxView::ADSBTxView(
&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<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -29,6 +29,7 @@
#include "message.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
using namespace adsb;
@@ -201,9 +202,12 @@ class ADSBTxView : public View {
-1
};*/
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
10000000 /* bandwidth */,
4000000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_adsb", app_settings::Mode::TX};
// tx_modes tx_mode = IDLE;
NavigationView& nav_;
+3 -18
View File
@@ -44,7 +44,7 @@ void AFSKRxView::focus() {
}
void AFSKRxView::update_freq(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
}
AFSKRxView::AFSKRxView(NavigationView& nav) {
@@ -62,14 +62,6 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
&button_modem_setup,
&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);
}
// Auto-configure modem for LCR RX (will be removed later)
update_freq(467225500); // 462713300
auto def_bell202 = &modem_defs[0];
@@ -81,15 +73,14 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
serial_format.bit_order = LSB_FIRST;
persistent_memory::set_serial_format(serial_format);
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -113,8 +104,6 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
}
@@ -167,10 +156,6 @@ 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();
+4 -3
View File
@@ -28,6 +28,7 @@
#include "ui_receiver.hpp"
#include "ui_record_view.hpp" // DEBUG
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "log_file.hpp"
#include "utility.hpp"
@@ -57,9 +58,9 @@ class AFSKRxView : public View {
private:
void on_data(uint32_t value, bool is_data);
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_afsk", app_settings::Mode::RX};
uint8_t console_color{0};
uint32_t prev_value{0};
+3 -17
View File
@@ -74,7 +74,7 @@ void APRSRxView::focus() {
}
void APRSRxView::update_freq(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
}
APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
@@ -92,14 +92,6 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
&record_view,
&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);
@@ -119,15 +111,14 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
}
};
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -143,8 +134,6 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
}
@@ -211,9 +200,6 @@ void APRSRxView::on_show() {
}
APRSRxView::~APRSRxView() {
// save app settings
settings.save("rx_aprs", &app_settings);
audio::output::stop();
receiver_model.disable();
baseband::shutdown();
+4 -3
View File
@@ -29,6 +29,7 @@
#include "ui_record_view.hpp" // DEBUG
#include "ui_geomap.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "recent_entries.hpp"
#include "ui_tabview.hpp"
@@ -187,9 +188,9 @@ class APRSRxView : public View {
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{};
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_aprs", app_settings::Mode::RX};
uint8_t console_color{0};
std::string str_log{""};
+3 -20
View File
@@ -26,7 +26,6 @@
#include "aprs.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
#include "cpld_update.hpp"
#include "baseband_api.hpp"
#include "portapack_shared_memory.hpp"
#include "portapack_persistent_memory.hpp"
@@ -44,13 +43,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void APRSTXView::start_tx() {
@@ -62,9 +56,6 @@ void APRSTXView::start_tx() {
// uint8_t * bb_data_ptr = shared_memory.bb_data.data;
// text_payload.set(to_string_hex_array(bb_data_ptr + 56, 15));
transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency());
transmitter_model.set_sampling_rate(AFSK_TX_SAMPLERATE);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_afsk_data(
@@ -97,14 +88,6 @@ APRSTXView::APRSTXView(NavigationView& nav) {
&button_set,
&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,
@@ -116,9 +99,9 @@ APRSTXView::APRSTXView(NavigationView& nav) {
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+8 -3
View File
@@ -27,8 +27,10 @@
#include "ui_transmitter.hpp"
#include "message.hpp"
#include "modems.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
namespace ui {
@@ -43,9 +45,12 @@ class APRSTXView : public View {
std::string title() const override { return "APRS TX"; };
private:
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
AFSK_TX_SAMPLERATE /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_aprs", app_settings::Mode::TX};
std::string payload{""};
+10 -26
View File
@@ -24,7 +24,6 @@
#include "string_format.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
@@ -137,13 +136,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
BHTView::BHTView(NavigationView& nav) {
@@ -157,21 +151,12 @@ BHTView::BHTView(NavigationView& nav) {
&progressbar,
&tx_view});
// 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<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
@@ -233,7 +218,6 @@ EPARView::EPARView(
field_city.set_value(0);
field_group.set_selected_index(2);
field_city.on_change = [this](int32_t) { generate_message(); };
field_group.on_change = [this](size_t, int32_t) { generate_message(); };
@@ -243,11 +227,11 @@ EPARView::EPARView(
size_t n = 0;
for (auto& relay_state : relay_states) {
relay_state.on_change = relay_state_fn;
relay_state.set_parent_rect({static_cast<Coord>(90 + (n * 36)),
80,
24, 24});
relay_state.set_options(relay_options);
relay_state.on_change = relay_state_fn; // NB: set after set_options to avoid startup call.
add_child(&relay_state);
n++;
}
@@ -316,11 +300,11 @@ XylosView::XylosView(
};
field_header_a.on_change = field_fn;
field_header_b.on_change = [this](int32_t) { generate_message(); };
field_city.on_change = [this](int32_t) { generate_message(); };
field_family.on_change = [this](int32_t) { generate_message(); };
field_subfamily.on_change = [this](int32_t) { generate_message(); };
field_receiver.on_change = [this](int32_t) { generate_message(); };
field_header_b.on_change = field_fn;
field_city.on_change = field_fn;
field_family.on_change = field_fn;
field_subfamily.on_change = field_fn;
field_receiver.on_change = field_fn;
checkbox_wcsubfamily.on_select = [this](Checkbox&, bool v) {
field_subfamily.set_focusable(!v);
@@ -341,11 +325,11 @@ XylosView::XylosView(
size_t n = 0;
for (auto& relay_state : relay_states) {
relay_state.on_change = relay_state_fn;
relay_state.set_parent_rect({static_cast<Coord>(54 + (n * 36)),
134,
24, 24});
relay_state.set_options(relay_options);
relay_state.on_change = relay_state_fn; // NB: set after set_options to avoid startup call.
add_child(&relay_state);
n++;
}
+4 -3
View File
@@ -32,6 +32,7 @@
#include "transmitter_model.hpp"
#include "encoders.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
namespace ui {
@@ -165,9 +166,9 @@ class BHTView : public View {
std::string title() const override { return "BHT TX"; };
private:
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_bht", app_settings::Mode::TX};
void on_tx_progress(const uint32_t progress, const bool done);
void start_tx();
+3 -18
View File
@@ -41,7 +41,7 @@ void BTLERxView::focus() {
}
void BTLERxView::update_freq(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
}
BTLERxView::BTLERxView(NavigationView& nav) {
@@ -56,14 +56,6 @@ BTLERxView::BTLERxView(NavigationView& nav) {
&button_modem_setup,
&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);
}
// Auto-configure modem for LCR RX (will be removed later)
update_freq(2426000000);
auto def_bell202 = &modem_defs[0];
@@ -75,15 +67,14 @@ BTLERxView::BTLERxView(NavigationView& nav) {
serial_format.bit_order = LSB_FIRST;
persistent_memory::set_serial_format(serial_format);
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -98,8 +89,6 @@ BTLERxView::BTLERxView(NavigationView& nav) {
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(4000000);
receiver_model.set_baseband_bandwidth(4000000);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable();
}
@@ -148,10 +137,6 @@ 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();
+7 -3
View File
@@ -28,6 +28,7 @@
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_record_view.hpp" // DEBUG
#include "utility.hpp"
@@ -46,9 +47,12 @@ class BTLERxView : public View {
private:
void on_data(uint32_t value, bool is_data);
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{
4000000 /* bandwidth */,
4000000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_btle", app_settings::Mode::RX};
uint8_t console_color{0};
uint32_t prev_value{0};
+3 -20
View File
@@ -23,7 +23,6 @@
#include "ui_coasterp.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "portapack_persistent_memory.hpp"
#include <cstring>
@@ -38,13 +37,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void CoasterPagerView::generate_frame() {
@@ -73,8 +67,6 @@ void CoasterPagerView::generate_frame() {
void CoasterPagerView::start_tx() {
generate_frame();
transmitter_model.set_sampling_rate(2280000);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_fsk_data(19 * 8, 2280000 / 1000, 5000, 32);
@@ -123,15 +115,6 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) {
&text_message,
&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);
@@ -141,9 +124,9 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) {
generate_frame();
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -28,6 +28,7 @@
#include "message.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
namespace ui {
@@ -50,9 +51,12 @@ class CoasterPagerView : public View {
tx_modes tx_mode = IDLE;
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_coaster", app_settings::Mode::TX};
void start_tx();
void generate_frame();
+17 -3
View File
@@ -25,6 +25,7 @@
#include "radio.hpp"
#include "string_format.hpp"
#include "crc.hpp"
#include "audio.hpp"
@@ -381,22 +382,35 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push<DebugPeripheralsMenuView>(); }},
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav]() { nav.push<DebugControlsView>(); }},
{"Pmem", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
{"P.Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
});
set_max_rows(2); // allow wider buttons
}
/* DebugPmemView *********************************************************/
uint32_t pmem_checksum(volatile const uint32_t data[63]) {
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
for (size_t i = 0; i < 63; i++) {
const auto word = data[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();
}
DebugPmemView::DebugPmemView(NavigationView& nav)
: data{*reinterpret_cast<pmem_data*>(memory::map::backup_ram.base())}, registers_widget(RegistersWidgetConfig{page_size, 8}, std::bind(&DebugPmemView::registers_widget_feed, this, std::placeholders::_1)) {
static_assert(sizeof(pmem_data) == memory::map::backup_ram.size());
add_children({&text_page, &registers_widget, &text_checksum, &button_ok});
add_children({&text_page, &registers_widget, &text_checksum, &text_checksum2, &button_ok});
registers_widget.set_parent_rect({0, 32, 240, 192});
text_checksum.set("Size: " + to_string_dec_uint(portapack::persistent_memory::data_size()) + " CRC: " + to_string_hex(data.check_value, 8));
text_checksum.set("Size: " + to_string_dec_uint(portapack::persistent_memory::data_size(), 3) + " CRC: " + to_string_hex(data.check_value, 8));
text_checksum2.set("Calculated CRC: " + to_string_hex(pmem_checksum(data.regfile), 8));
button_ok.on_select = [&nav](Button&) {
nav.pop();
+4 -3
View File
@@ -269,7 +269,7 @@ class DebugPmemView : public View {
DebugPmemView(NavigationView& nav);
void focus() override;
bool on_encoder(const EncoderEvent delta) override;
std::string title() const override { return "Pmem"; }
std::string title() const override { return "P.Mem Debug"; }
private:
struct pmem_data {
@@ -282,13 +282,14 @@ class DebugPmemView : public View {
int32_t page{0};
const pmem_data& data;
volatile const pmem_data& data;
Text text_page{{16, 16, 208, 16}};
RegistersWidget registers_widget;
Text text_checksum{{16, 240, 208, 16}};
Text text_checksum{{16, 232, 208, 16}};
Text text_checksum2{{16, 248, 208, 16}};
Button button_ok{
{240 / 3, 270, 240 / 3, 24},
+3 -20
View File
@@ -24,7 +24,6 @@
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "cpld_update.hpp"
using namespace portapack;
@@ -200,13 +199,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // ghost signal c/m to the problem at the exit .
baseband::shutdown(); // better this function after load_sram()
baseband::shutdown();
}
void EncodersView::update_progress() {
@@ -266,8 +260,6 @@ void EncodersView::start_tx(const bool scan) {
repeat_index = 1;
update_progress();
transmitter_model.set_sampling_rate(OOK_SAMPLERATE);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_ook_data(
@@ -290,19 +282,10 @@ EncodersView::EncodersView(
&progressbar,
&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<FrequencyKeypadView>(transmitter_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -27,6 +27,7 @@
#include "encoders.hpp"
#include "de_bruijn.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
using namespace encoders;
@@ -183,9 +184,12 @@ class EncodersView : public View {
SCAN
};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_ook", app_settings::Mode::TX};
tx_modes tx_mode = IDLE;
uint32_t repeat_index{0};
+2 -6
View File
@@ -25,7 +25,6 @@
#include "ui_freqman.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "string_format.hpp"
using namespace portapack;
@@ -180,13 +179,12 @@ void JammerView::focus() {
JammerView::~JammerView() {
transmitter_model.disable();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void JammerView::on_retune(const rf::Frequency freq, const uint32_t range) {
if (freq) {
transmitter_model.set_tuning_frequency(freq);
transmitter_model.set_target_frequency(freq);
text_range_number.set(to_string_dec_uint(range, 2));
}
}
@@ -261,9 +259,7 @@ void JammerView::start_tx() {
button_transmit.set_style(&style_cancel);
button_transmit.set_text("STOP");
transmitter_model.set_sampling_rate(3072000U);
transmitter_model.set_rf_amp(field_amp.value());
transmitter_model.set_baseband_bandwidth(3500000U);
transmitter_model.set_tx_gain(field_gain.value());
transmitter_model.enable();
+5
View File
@@ -29,6 +29,7 @@
#include "message.hpp"
#include "jammer.hpp"
#include "lfsr_random.hpp"
#include "radio_state.hpp"
using namespace jammer;
@@ -99,6 +100,10 @@ class JammerView : public View {
private:
NavigationView& nav_;
TxRadioState radio_state_{
3500000 /* bandwidth */,
3072000 /* sampling rate */
};
void start_tx();
void on_timer();
+4 -8
View File
@@ -23,7 +23,6 @@
#include "ui_keyfob.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "string_format.hpp"
using namespace portapack;
@@ -141,8 +140,7 @@ KeyfobView::~KeyfobView() {
settings.save("tx_keyfob", &app_settings);
transmitter_model.disable();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void KeyfobView::update_progress(const uint32_t progress) {
@@ -190,8 +188,6 @@ void KeyfobView::start_tx() {
size_t bitstream_length = generate_frame();
transmitter_model.set_sampling_rate(OOK_SAMPLERATE);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_ook_data(
@@ -236,12 +232,12 @@ KeyfobView::KeyfobView(
options_make.set_selected_index(0);
transmitter_model.set_tuning_frequency(433920000); // Fixed 433.92MHz
transmitter_model.set_target_frequency(433920000); // Fixed 433.92MHz
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -24,6 +24,7 @@
#include "ui_transmitter.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "encoders.hpp"
using namespace encoders;
@@ -42,9 +43,12 @@ class KeyfobView : public View {
private:
NavigationView& nav_;
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_keyfob", , app_settings::Mode::TX};
// 1013210ns / bit
static constexpr uint32_t subaru_samples_per_bit = (OOK_SAMPLERATE * 0.00101321);
+3 -22
View File
@@ -24,10 +24,8 @@
#include "ui_modemsetup.hpp"
#include "lcr.hpp"
#include "modems.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "cpld_update.hpp"
#include "serializer.hpp"
@@ -40,13 +38,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
/*
@@ -134,9 +127,6 @@ void LCRView::start_tx(const bool scan) {
modems::generate_data(lcr::generate_message(rgsb, litterals_list, options_ec.selected_index()), lcr_message_data);
transmitter_model.set_tuning_frequency(persistent_memory::tuned_frequency());
transmitter_model.set_sampling_rate(AFSK_TX_SAMPLERATE);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
memcpy(shared_memory.bb_data.data, lcr_message_data, sizeof(lcr_message_data));
@@ -176,15 +166,6 @@ LCRView::LCRView(NavigationView& nav) {
&button_clear,
&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) {
@@ -251,9 +232,9 @@ LCRView::LCRView(NavigationView& nav) {
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+8 -3
View File
@@ -26,8 +26,10 @@
#include "ui_transmitter.hpp"
#include "message.hpp"
#include "modems.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -79,9 +81,12 @@ class LCRView : public View {
SCAN
};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
AFSK_TX_SAMPLERATE /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_lcr", app_settings::Mode::TX};
tx_modes tx_mode = IDLE;
uint8_t scan_count{0}, scan_index{0};
+13 -37
View File
@@ -35,13 +35,6 @@ void LevelView::focus() {
}
LevelView::~LevelView() {
// save app settings
app_settings.lna = field_lna.value();
app_settings.vga = field_vga.value();
app_settings.rx_amp = field_rf_amp.value();
settings.save("level", &app_settings);
receiver_model.disable();
baseband::shutdown();
}
@@ -71,42 +64,31 @@ LevelView::LevelView(NavigationView& nav)
change_mode(NFM_MODULATION); // Start on AM
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector
// HELPER: Pre-setting a manual range, based on stored frequency
freq = persistent_memory::tuned_frequency();
receiver_model.set_tuning_frequency(freq);
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
// load auto common app settings
auto rc = settings.load("level", &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);
receiver_model.set_rf_amp(app_settings.rx_amp);
}
freq_ = receiver_model.target_frequency();
button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>");
button_frequency.on_select = [this, &nav](ButtonWithEncoder& button) {
auto new_view = nav_.push<FrequencyKeypadView>(freq);
auto new_view = nav_.push<FrequencyKeypadView>(freq_);
new_view->on_changed = [this, &button](rf::Frequency f) {
freq = f;
receiver_model.set_tuning_frequency(f); // Retune to actual freq
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
freq_ = f;
receiver_model.set_target_frequency(f); // Retune to actual freq
button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>");
};
};
button_frequency.on_change = [this]() {
int64_t def_step = freqman_entry_get_step_value(step_mode.selected_index());
freq = freq + (button_frequency.get_encoder_delta() * def_step);
if (freq < 1) {
freq = 1;
freq_ = freq_ + (button_frequency.get_encoder_delta() * def_step);
if (freq_ < 1) {
freq_ = 1;
}
if (freq > (MAX_UFREQ - def_step)) {
freq = MAX_UFREQ;
if (freq_ > (MAX_UFREQ - def_step)) {
freq_ = MAX_UFREQ;
}
button_frequency.set_encoder_delta(0);
receiver_model.set_tuning_frequency(freq); // Retune to actual freq
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
receiver_model.set_target_frequency(freq_); // Retune to actual freq
button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>");
};
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
@@ -196,8 +178,6 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
receiver_model.set_am_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
break;
case NFM_MODULATION:
@@ -208,8 +188,6 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.set_nbfm_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
break;
case WFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
@@ -219,8 +197,6 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.set_wfm_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
break;
default:
+8 -5
View File
@@ -38,6 +38,7 @@
#include "string_format.hpp"
#include "file.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -53,13 +54,18 @@ class LevelView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_level", app_settings::Mode::RX};
size_t change_mode(freqman_index_t mod_type);
void on_statistics_update(const ChannelStatistics& statistics);
void set_display_freq(int64_t freq);
// TODO: needed?
int32_t db{0};
long long int MAX_UFREQ = {7200000000}; // maximum usable freq
rf::Frequency freq = {0};
rf::Frequency freq_ = {0};
Labels labels{
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()},
@@ -104,7 +110,7 @@ class LevelView : public View {
{"audio off", 0},
{"audio on", 1}
//{"tone on", 2},
//{"tone off", 2},
//{"tone off", 3},
}};
Text text_ctcss{
@@ -168,9 +174,6 @@ class LevelView : public View {
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
};
} /* namespace ui */
@@ -22,6 +22,9 @@
*/
#include "ui_looking_glass_app.hpp"
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
using namespace portapack;
@@ -38,7 +41,7 @@ GlassView::~GlassView() {
void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power) {
if (mode == LOOKING_GLASS_SINGLEPASS) {
// analog audio app like view
// <20MHz spectrum mode
if (bin < 120) {
if (spectrum.db[SPEC_NB_BINS - 120 + bin] > max_power)
max_power = spectrum.db[SPEC_NB_BINS - 120 + bin];
@@ -47,15 +50,13 @@ void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint
max_power = spectrum.db[bin - 120];
}
} else {
// view is made in multiple pass, use original bin picking
// FAST mode: center 12 bins are ignored in fast mode , (DC spike is blanked) leftmost and rightmost 2 bins are ignored
// SLOW mode: leftmost 'offset' bins are ignored
// FAST or SLOW mode
if (bin < 120) {
if (spectrum.db[SPEC_NB_BINS - offset - 120 + bin] > max_power)
max_power = spectrum.db[SPEC_NB_BINS - offset - 120 + bin];
if (spectrum.db[134 + bin] > max_power)
max_power = spectrum.db[134 + bin];
} else {
if (spectrum.db[offset + bin - 120] > max_power)
max_power = spectrum.db[offset + bin - 120];
if (spectrum.db[bin - 118] > max_power)
max_power = spectrum.db[bin - 118];
}
}
}
@@ -66,7 +67,7 @@ rf::Frequency GlassView::get_freq_from_bin_pos(uint8_t pos) {
// starting from the middle, minus 8 ignored bin on each side. Since pos is [-120,120] after the (pos - 120), it's divided by SCREEN_W(240)/2 => 120
freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (SCREEN_W / 2);
} else
freq_at_pos = f_min - (offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W;
freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W;
return freq_at_pos;
}
@@ -77,23 +78,6 @@ void GlassView::on_marker_change() {
PlotMarker(marker_pixel_index); // Refresh marker on screen
}
// Returns the next multiple of num that is a multiple of multiplier
int64_t GlassView::next_mult_of(int64_t num, int64_t multiplier) {
return ((num / multiplier) + 1) * multiplier;
}
void GlassView::adjust_range(int64_t* f_min, int64_t* f_max, int64_t width) {
int64_t span = *f_max - *f_min;
int64_t num_intervals = span / width;
if (span % width != 0) {
num_intervals++;
}
int64_t new_span = num_intervals * width;
int64_t delta_span = (new_span - span) / 2;
*f_min -= delta_span;
*f_max += delta_span;
}
void GlassView::retune() {
// Start a new sweep.
// Tune rx for this new slice directly because the model
@@ -166,6 +150,31 @@ void GlassView::add_spectrum_pixel(uint8_t power) {
}
}
bool GlassView::process_bins(uint8_t* powerlevel) {
bins_Hz_size += each_bin_size; // add pixel to fulfilled bag of Hz
if (bins_Hz_size >= marker_pixel_step) // new pixel fullfilled
{
if (*powerlevel > min_color_power)
add_spectrum_pixel(*powerlevel); // Pixel will represent max_power
else
add_spectrum_pixel(0); // Filtered out, show black
*powerlevel = 0;
if (!pixel_index) // Received indication that a waterfall line has been completed
{
bins_Hz_size = 0; // Since this is an entire pixel line, we don't carry "Pixels into next bin"
if (mode != LOOKING_GLASS_SINGLEPASS) {
f_center = f_center_ini;
retune();
} else
baseband::spectrum_streaming_start();
return true; // signal a new line
}
bins_Hz_size -= marker_pixel_step; // reset bins size, but carrying the eventual excess Hz into next pixel
}
return false;
}
// Apparently, the spectrum object returns an array of SPEC_NB_BINS (256) bins
// Each having the radio signal power for it's corresponding frequency slot
void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
@@ -174,31 +183,19 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
// we actually need SCREEN_W (240) of those bins
for (bin = 0; bin < bin_length; bin++) {
get_max_power(spectrum, bin, max_power);
if (ignore_dc && bin == 119) {
bins_Hz_size += 12 * each_bin_size; // add the ignored DC spike to "pixel fulfilled bag of Hz"
}
bins_Hz_size += each_bin_size; // add this bin Hz count into the "pixel fulfilled bag of Hz"
if (bins_Hz_size >= marker_pixel_step) // new pixel fullfilled
{
if (min_color_power < max_power)
add_spectrum_pixel(max_power); // Pixel will represent max_power
else
add_spectrum_pixel(0); // Filtered out, show black
max_power = 0;
if (!pixel_index) // Received indication that a waterfall line has been completed
{
bins_Hz_size = 0; // Since this is an entire pixel line, we don't carry "Pixels into next bin"
if (mode != LOOKING_GLASS_SINGLEPASS) {
f_center = f_center_ini;
retune();
} else
baseband::spectrum_streaming_start();
return; // signal a new line
// process dc spike if enable
if (bin == 119) {
uint8_t next_max_power = 0;
get_max_power(spectrum, bin + 1, next_max_power);
for (uint8_t it = 0; it < ignore_dc; it++) {
uint8_t med_max_power = (max_power + next_max_power) / 2; // due to the way process_bins works we have to keep resetting the color
if (process_bins(&med_max_power) == true)
return; // new line signaled, return
}
bins_Hz_size -= marker_pixel_step; // reset bins size, but carrying the eventual excess Hz into next pixel
}
// process actual bin
if (process_bins(&max_power) == true)
return; // new line signaled, return
}
if (mode != LOOKING_GLASS_SINGLEPASS) {
f_center += looking_glass_step;
@@ -225,36 +222,33 @@ void GlassView::on_range_changed() {
f_max = f_max * MHZ_DIV;
looking_glass_range = f_max - f_min;
if (looking_glass_range <= LOOKING_GLASS_SLICE_WIDTH_MAX) {
adjust_range(&f_min, &f_max, SCREEN_W);
looking_glass_range = f_max - f_min;
// if the view is done in one pass, show it like in analog_audio_app
mode = LOOKING_GLASS_SINGLEPASS;
offset = 0;
offset = 2;
bin_length = SCREEN_W;
ignore_dc = 0;
looking_glass_bandwidth = looking_glass_range;
looking_glass_sampling_rate = looking_glass_bandwidth;
each_bin_size = looking_glass_bandwidth / SCREEN_W;
looking_glass_step = looking_glass_bandwidth;
f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
} else { // if ( mode == LOOKING_GLASS_SLOWSCAN || mode == LOOKING_GLASS_FASTSCAN )
f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
portapack::display.fill_rectangle({17 * 8, 4 * 16, 2 * 8, 16}, Color::black()); // Clear old marker and whole marker rectangle btw
} else {
// view is made in multiple pass, use original bin picking
mode = scan_type.selected_index_value();
if (mode == LOOKING_GLASS_FASTSCAN) {
offset = 2;
bin_length = SCREEN_W;
ignore_dc = 1;
} else { // if( mode == LOOKING_GLASS_SLOWSCAN )
offset = 16;
bin_length = 80;
ignore_dc = 0;
}
adjust_range(&f_min, &f_max, SCREEN_W);
looking_glass_range = f_max - f_min;
looking_glass_bandwidth = LOOKING_GLASS_SLICE_WIDTH_MAX;
looking_glass_sampling_rate = LOOKING_GLASS_SLICE_WIDTH_MAX;
each_bin_size = LOOKING_GLASS_SLICE_WIDTH_MAX / SPEC_NB_BINS;
looking_glass_step = (bin_length + (ignore_dc * 12)) * each_bin_size;
if (mode == LOOKING_GLASS_FASTSCAN) {
offset = 2;
ignore_dc = 4;
bin_length = SCREEN_W;
} else { // if( mode == LOOKING_GLASS_SLOWSCAN )
offset = 2;
bin_length = 80;
ignore_dc = 0;
}
looking_glass_step = (bin_length + ignore_dc) * each_bin_size;
f_center_ini = f_min - (offset * each_bin_size) + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
}
search_span = looking_glass_range / MHZ_DIV;
@@ -280,7 +274,7 @@ void GlassView::on_range_changed() {
receiver_model.set_squelch_level(0);
f_center = f_center_ini; // Reset sweep into first slice
baseband::set_spectrum(looking_glass_bandwidth, field_trigger.value());
receiver_model.set_tuning_frequency(f_center); // tune rx for this slice
receiver_model.set_target_frequency(f_center); // tune rx for this slice
}
void GlassView::PlotMarker(uint8_t pos) {
@@ -476,7 +470,7 @@ GlassView::GlassView(
};
button_marker.on_select = [this](ButtonWithEncoder&) {
receiver_model.set_tuning_frequency(marker); // Center tune rx in marker freq.
receiver_model.set_target_frequency(marker); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
@@ -500,7 +494,7 @@ GlassView::GlassView(
};
button_jump.on_select = [this](Button&) {
receiver_model.set_tuning_frequency(max_freq_hold); // Center tune rx in marker freq.
receiver_model.set_target_frequency(max_freq_hold); // Center tune rx in marker freq.
receiver_model.set_frequency_step(MHZ_DIV); // Preset a 1 MHz frequency step into RX -> AUDIO
nav_.pop();
nav_.push<AnalogAudioView>(); // Jump into audio view
@@ -527,71 +521,47 @@ GlassView::GlassView(
}
void GlassView::load_Presets() {
File presets_file; // LOAD /WHIPCALC/ANTENNAS.TXT from microSD
auto result = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
presets_db.clear(); // Start with fresh db
if (result.is_valid()) {
presets_Default(); // There is no txt, store a default range
} else {
std::string line; // There is a txt file
char one_char[1]; // Read it char by char
for (size_t pointer = 0; pointer < presets_file.size(); pointer++) {
presets_file.seek(pointer);
presets_file.read(one_char, 1);
if ((int)one_char[0] > 31) { // ascii space upwards
line += one_char[0]; // Add it to the textline
} else if (one_char[0] == '\n') { // New Line
txtline_process(line); // make sense of this textline
line.clear(); // Ready for next textline
}
File presets_file;
auto error = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
presets_db.clear();
if (!error) {
auto reader = FileLineReader(presets_file);
for (const auto& line : reader) {
if (line.length() == 0 || line[0] == '#')
continue;
auto cols = split_string(line, ',');
if (cols.size() != 3)
continue;
preset_entry entry{};
parse_int(cols[0], entry.min);
parse_int(cols[1], entry.max);
entry.label = trimr(cols[2]);
if (entry.min == 0 || entry.max == 0 || entry.min >= entry.max)
continue; // Invalid line.
presets_db.emplace_back(std::move(entry));
}
if (line.length() > 0)
txtline_process(line); // Last line had no newline at end ?
if (!presets_db.size())
presets_Default(); // no antenna on txt, use default
}
// Couldn't load any from the file, load a default instead.
if (presets_db.empty())
presets_Default();
populate_Presets();
}
void GlassView::txtline_process(std::string& line) {
if (line.find("#") != std::string::npos)
return; // Line is just a comment
size_t comma = line.find(","); // Get first comma position
if (comma == std::string::npos)
return; // No comma at all
size_t previous = 0;
preset_entry new_preset;
new_preset.min = std::stoi(line.substr(0, comma));
if (!new_preset.min)
return; // No frequency!
previous = comma + 1;
comma = line.find(",", previous); // Search for next delimiter
if (comma == std::string::npos)
return; // No comma at all
new_preset.max = std::stoi(line.substr(previous, comma - previous));
if (!new_preset.max)
return; // No frequency!
new_preset.label = line.substr(comma + 1);
if (new_preset.label.size() == 0)
return; // No label ?
presets_db.push_back(new_preset); // Add this preset.
}
void GlassView::populate_Presets() {
using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>;
options_t entries;
for (preset_entry preset : presets_db) { // go thru all available presets
for (const auto& preset : presets_db)
entries.emplace_back(preset.label, entries.size());
}
range_presets.set_options(entries);
}
@@ -27,6 +27,7 @@
#include "ui.hpp"
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "radio_state.hpp"
#include "receiver_model.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
@@ -37,6 +38,7 @@
#include "spectrum_color_lut.hpp"
namespace ui {
#define LOOKING_GLASS_SLICE_WIDTH_MAX 20000000
#define MHZ_DIV 1000000
@@ -68,6 +70,7 @@ class GlassView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{};
struct preset_entry {
rf::Frequency min{};
@@ -81,12 +84,12 @@ class GlassView : public View {
void get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power);
rf::Frequency get_freq_from_bin_pos(uint8_t pos);
void on_marker_change();
int64_t next_mult_of(int64_t num, int64_t multiplier);
void adjust_range(int64_t* f_min, int64_t* f_max, int64_t width);
void retune();
bool move_to_next_position();
bool process_bins(uint8_t* powerlevel);
void on_channel_spectrum(const ChannelSpectrum& spectrum);
void do_timers();
int64_t next_mult_of(int64_t num, int64_t multiplier);
void adjust_range(int64_t* f_min, int64_t* f_max, int64_t width);
void on_range_changed();
void on_lna_changed(int32_t v_db);
void on_vga_changed(int32_t v_db);
+22 -31
View File
@@ -30,7 +30,6 @@ using wolfson::wm8731::WM8731;
#include "tonesets.hpp"
#include "portapack_hal.hpp"
#include "cpld_update.hpp"
#include "string_format.hpp"
#include "irq_controls.hpp"
@@ -68,6 +67,7 @@ void MicTXView::on_tx_progress(const bool done) {
}
void MicTXView::configure_baseband() {
// TODO: Can this use the transmitter model instead?
baseband::set_audiotx_config(
sampling_rate / 20, // Update vu-meter at 20Hz
transmitting ? transmitter_model.channel_bandwidth() : 0,
@@ -86,7 +86,7 @@ void MicTXView::set_tx(bool enable) {
rxaudio(false); // Then turn off audio RX
transmitting = true;
configure_baseband();
transmitter_model.set_tuning_frequency(tx_frequency); // Now,no need: transmitter_model.set_tx_gain(tx_gain), nor (rf_amp);
transmitter_model.set_target_frequency(tx_frequency); // Now, no need: transmitter_model.set_tx_gain(tx_gain), nor (rf_amp);
transmitter_model.enable();
portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming
} else {
@@ -140,14 +140,6 @@ void MicTXView::do_timing() {
}
}
/* Hmmmm. Maybe useless now.
void MicTXView::on_tuning_frequency_changed(rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
//if ( rx_enabled )
receiver_model.set_tuning_frequency(f); //Update freq also for RX
}
*/
void MicTXView::rxaudio(bool is_on) {
if (is_on) {
audio::input::stop();
@@ -170,18 +162,15 @@ void MicTXView::rxaudio(bool is_on) {
// receiver_model.set_nbfm_configuration(n); is called above , depending user's selection (8k5, 11k, 16k).
}
}
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
// receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
if (bool_same_F_tx_rx_enabled) // when stop TX ,define to which freq RX we return
receiver_model.set_tuning_frequency(tx_frequency); // Update freq also for RX = TX
receiver_model.set_target_frequency(tx_frequency); // Update freq also for RX = TX
else
receiver_model.set_tuning_frequency(rx_frequency); // Now with seperate freq controls!
receiver_model.set_target_frequency(rx_frequency); // Now with separate freq controls!
receiver_model.set_lna(rx_lna);
receiver_model.set_vga(rx_vga);
receiver_model.set_rf_amp(rx_amp);
receiver_model.enable();
hackrf::cpld::load_sram_no_verify(); // to have a good RX without any ghost inside Mic App
audio::output::start();
} else { // These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); // This fixes something with AM RX...
@@ -294,11 +283,11 @@ MicTXView::MicTXView(
}
ak4951_alc_and_wm8731_boost_GUI = v; // 0,..4 WM8731_boost dB's options, (combination boost on/off , and effective gain in captured data >>x)
audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731) , set up the proper wm_boost on/off , 0..4 (0,1) boost_on , (2,3,4) boost_0ff
configure_baseband(); // to update in real timme,sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc -
configure_baseband(); // to update in real time, sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc -
};
options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's .
} else {
shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8)
shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8)
options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) {
ak4951_alc_and_wm8731_boost_GUI = v; // 0,..11, AK4951 Mic -Automatic volume Level Control options,
audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options
@@ -308,16 +297,16 @@ MicTXView::MicTXView(
// options_ak4951_alc_mode.set_selected_index(0);
tx_frequency = transmitter_model.tuning_frequency();
field_frequency.set_value(transmitter_model.tuning_frequency());
tx_frequency = transmitter_model.target_frequency();
field_frequency.set_value(transmitter_model.target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
tx_frequency = f;
if (!rx_enabled) { // not activated receiver. just update freq TX
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
} else { // activated receiver.
if (bool_same_F_tx_rx_enabled) // user selected common freq- TX = RX
receiver_model.set_tuning_frequency(f); // Update common freq also for RX
receiver_model.set_target_frequency(f); // Update common freq also for RX
}
};
field_frequency.on_edit = [this, &nav]() {
@@ -327,10 +316,10 @@ MicTXView::MicTXView(
new_view->on_changed = [this](rf::Frequency f) {
tx_frequency = f;
if (!rx_enabled) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
} else {
if (bool_same_F_tx_rx_enabled)
receiver_model.set_tuning_frequency(f); // Update freq also for RX
receiver_model.set_target_frequency(f); // Update freq also for RX
}
this->field_frequency.set_value(f);
set_dirty();
@@ -492,7 +481,7 @@ MicTXView::MicTXView(
bool_same_F_tx_rx_enabled = v;
field_rxfrequency.hidden(v); // Hide or show separated freq RX field . (When no hide user can enter down indep. freq for RX)
set_dirty(); // Refresh GUI interface
receiver_model.set_tuning_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it
receiver_model.set_target_frequency(v ? tx_frequency : rx_frequency); // To go to the proper tuned freq. when toggling it
};
field_va_level.on_change = [this](int32_t v) {
@@ -542,13 +531,13 @@ MicTXView::MicTXView(
field_squelch.set_value(0);
receiver_model.set_squelch_level(0);
rx_frequency = receiver_model.tuning_frequency();
rx_frequency = receiver_model.target_frequency();
field_rxfrequency.set_value(rx_frequency);
field_rxfrequency.set_step(receiver_model.frequency_step());
field_rxfrequency.on_change = [this](rf::Frequency f) { // available when field rxfrequency not hidden => user selected separated freq RX/TX-
rx_frequency = f;
if (rx_enabled)
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
};
field_rxfrequency.on_edit = [this, &nav]() { // available when field rxfrequency not hidden => user selected separated freq RX/TX-
focused_ui = 1;
@@ -557,7 +546,7 @@ MicTXView::MicTXView(
new_view->on_changed = [this](rf::Frequency f) {
rx_frequency = f;
if (rx_enabled)
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
this->field_rxfrequency.set_value(f);
set_dirty();
};
@@ -606,6 +595,9 @@ MicTXView::MicTXView(
}
};
// These shouldn't be necessary, but because
// this app uses both transmitter_model and directly
// configures the baseband, these end up being required.
transmitter_model.set_sampling_rate(sampling_rate);
transmitter_model.set_baseband_bandwidth(1750000);
@@ -617,12 +609,11 @@ MicTXView::MicTXView(
MicTXView::~MicTXView() {
audio::input::stop();
transmitter_model.set_tuning_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency.
transmitter_model.set_target_frequency(tx_frequency); // Save Tx frequency instead of Rx. Or maybe we need some "System Wide" changes to seperate Tx and Rx frequency.
transmitter_model.disable();
if (rx_enabled) // Also turn off audio rx if enabled
rxaudio(false);
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
} // namespace ui
+12 -1
View File
@@ -26,6 +26,8 @@
#define SHORT_UI true
#define NORMAL_UI false
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
@@ -71,7 +73,7 @@ class MicTXView : public View {
void update_vumeter();
void do_timing();
void set_tx(bool enable);
// void on_tuning_frequency_changed(rf::Frequency f);
// void on_target_frequency_changed(rf::Frequency f);
void on_tx_progress(const bool done);
void configure_baseband();
@@ -79,6 +81,15 @@ class MicTXView : public View {
void set_ptt_visibility(bool v);
RxRadioState rx_radio_state_{};
TxRadioState tx_radio_state_{
1750000 /* bandwidth */,
sampling_rate /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_mic", app_settings::Mode::RX_TX,
app_settings::Options::UseGlobalTargetFrequency};
bool transmitting{false};
bool va_enabled{false};
bool ptt_enabled{true};
+3 -21
View File
@@ -26,7 +26,6 @@
#include "baseband_api.hpp"
#include "hackrf_gpio.hpp"
#include "portapack_shared_memory.hpp"
#include "cpld_update.hpp"
#include "ui_textentry.hpp"
#include "string_format.hpp"
@@ -98,13 +97,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit .
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void MorseView::paint(Painter&) {
@@ -123,9 +117,6 @@ bool MorseView::start_tx() {
}
progressbar.set_max(symbol_count);
transmitter_model.set_sampling_rate(1536000U);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
if (modulation == CW) {
@@ -206,15 +197,6 @@ MorseView::MorseView(
&progressbar,
&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
@@ -251,9 +233,9 @@ MorseView::MorseView(
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -28,6 +28,7 @@
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
#include "message.hpp"
#include "volume.hpp"
@@ -68,9 +69,12 @@ class MorseView : public View {
std::string message{};
uint32_t time_units{0};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_morse", app_settings::Mode::TX};
enum modulation_t {
CW = 0,
+3 -18
View File
@@ -41,7 +41,7 @@ void NRFRxView::focus() {
}
void NRFRxView::update_freq(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
receiver_model.set_target_frequency(f);
}
NRFRxView::NRFRxView(NavigationView& nav) {
@@ -56,14 +56,6 @@ NRFRxView::NRFRxView(NavigationView& nav) {
&button_modem_setup,
&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);
}
// Auto-configure modem for LCR RX (will be removed later)
update_freq(2480000000);
auto def_bell202 = &modem_defs[0];
@@ -75,15 +67,14 @@ NRFRxView::NRFRxView(NavigationView& nav) {
serial_format.bit_order = LSB_FIRST;
persistent_memory::set_serial_format(serial_format);
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
@@ -98,8 +89,6 @@ NRFRxView::NRFRxView(NavigationView& nav) {
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(4000000);
receiver_model.set_baseband_bandwidth(4000000);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.enable();
}
@@ -151,10 +140,6 @@ 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();
+7 -3
View File
@@ -28,6 +28,7 @@
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_record_view.hpp" // DEBUG
#include "utility.hpp"
@@ -46,9 +47,12 @@ class NRFRxView : public View {
private:
void on_data(uint32_t value, bool is_data);
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
RxRadioState radio_state_{
4000000 /* bandwidth */,
4000000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_nrf", app_settings::Mode::RX};
uint8_t console_color{0};
uint32_t prev_value{0};
-2
View File
@@ -129,9 +129,7 @@ void NumbersStationView::start_tx() {
prepare_audio();
transmitter_model.set_sampling_rate(1536000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_audiotx_data(
+6
View File
@@ -34,6 +34,7 @@
#include "message.hpp"
#include "file.hpp"
#include "io_wave.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -54,6 +55,11 @@ class NumbersStationView : public View {
private:
NavigationView& nav_;
TxRadioState radio_state_{
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
// Sequencing state machine
enum segments {
IDLE = 0,
+2 -4
View File
@@ -77,11 +77,9 @@ void NuoptixView::transmit(bool setup) {
timecode = number_timecode.value();
}
transmitter_model.set_sampling_rate(1536000U);
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
transmitter_model.set_vga(40);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
dtmf_message[0] = '*'; // "Pre-tone for restart" method #1
@@ -156,9 +154,9 @@ NuoptixView::NuoptixView(
number_timecode.set_value(1);
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.target_frequency(f);
};
};
+6 -1
View File
@@ -33,6 +33,7 @@
#include "message.hpp"
#include "volume.hpp"
#include "audio.hpp"
#include "radio_state.hpp"
#define NUOPTIX_TONE_LENGTH ((TONES_SAMPLERATE * 0.049) - 1) // 49ms
@@ -54,9 +55,13 @@ class NuoptixView : public View {
IMPROVISE
};
TxRadioState radio_state_{
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
tx_modes tx_mode{IDLE};
void on_tuning_frequency_changed(rf::Frequency f);
void transmit(bool setup);
void on_tx_progress(const uint32_t progress, const bool done);
+185 -219
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyleft () 2022 NotPike
* Copyright (C) 2023 Kyle Reed, zxkmm
*
* This file is part of PortaPack.
*
@@ -22,10 +23,12 @@
*/
#include "ui_playlist.hpp"
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
#include "ui_fileman.hpp"
#include "io_file.hpp"
#include "utility.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
@@ -34,223 +37,209 @@
#include <fstream>
using namespace portapack;
namespace fs = std::filesystem;
/* TODO: wouldn't it be easier if the playlist were just a list of C16 files
* (and maybe delays) and then read the data file next to the C16 file? */
namespace ui {
void PlaylistView::set_ready() {
ready_signal = true;
}
void PlaylistView::load_file(std::filesystem::path playlist_path) {
void PlaylistView::load_file(const fs::path& playlist_path) {
File playlist_file;
auto error = playlist_file.open(playlist_path.string());
if (!error.is_valid()) {
std::string line;
char one_char[1];
for (size_t pointer = 0; pointer < playlist_file.size(); pointer++) {
playlist_file.seek(pointer);
playlist_file.read(one_char, 1);
if ((int)one_char[0] >= ' ') {
line += one_char[0];
} else if (one_char[0] == '\n') {
total_tracks++;
txtline_process(line);
line.clear();
}
}
if (line.length() > 0) {
total_tracks++;
txtline_process(line);
}
}
playlist_masterdb = playlist_db;
return;
}
void PlaylistView::txtline_process(std::string& line) {
playlist_entry new_item;
rf::Frequency f;
size_t previous = 0;
size_t current = line.find(',');
std::string freqs = line.substr(0, current);
previous = current + 1;
current = line.find(',', previous);
std::string file = line.substr(previous, current - previous);
previous = current + 1;
current = line.find(',', previous);
uint32_t sample_rate = strtoll(line.substr(previous).c_str(), nullptr, 10);
f = strtoll(freqs.c_str(), nullptr, 0);
new_item.replay_frequency = f;
new_item.replay_file = "/" + file;
new_item.sample_rate = sample_rate;
new_item.next_delay = 0;
playlist_db.push_back(std::move(new_item));
}
void PlaylistView::on_file_changed(std::filesystem::path new_file_path, rf::Frequency replay_frequency, uint32_t replay_sample_rate) {
File data_file;
// Get file size
auto data_open_error = data_file.open("/" + new_file_path.string());
if (!data_open_error.is_valid()) {
track_number++;
} else if (data_open_error.is_valid()) {
file_error("C16 file\n" + new_file_path.string() + "\nread error.");
if (error)
return;
auto reader = FileLineReader(playlist_file);
for (const auto& line : reader) {
if (line.length() == 0 || line[0] == '#')
continue; // Empty or comment line.
auto cols = split_string(line, ',');
if (cols.size() < 3)
continue; // Line doesn't have enough columns.
playlist_entry entry{};
parse_int(cols[0], entry.replay_frequency);
parse_int(cols[2], entry.sample_rate);
if (entry.replay_frequency == 0 || entry.sample_rate == 0)
continue; // Invalid freq or rate.
entry.replay_file = fs::path{u"/"} + std::string{cols[1]};
if (cols.size() == 4) // Optional delay value.
parse_int(cols[3], entry.initial_delay);
playlist_db_.emplace_back(std::move(entry));
}
}
file_path = new_file_path;
field_frequency.set_value(replay_frequency);
void PlaylistView::on_file_changed(const fs::path& new_file_path) {
stop();
reset();
sample_rate = replay_sample_rate;
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
auto file_size = data_file.size();
auto duration = (file_size * 1000) / (2 * 2 * sample_rate);
progressbar.set_max(file_size);
text_filename.set(file_path.filename().string().substr(0, 12));
text_duration.set(to_string_time_ms(duration));
// text_track.set(std::to_string(track_number) + "/" + std::to_string(total_tracks));
playlist_path_ = new_file_path;
playlist_db_.clear();
load_file(playlist_path_);
update_ui();
button_play.focus();
}
void PlaylistView::on_tx_progress(const uint32_t progress) {
progressbar.set_value(progress);
void PlaylistView::reset() {
current_track_ = 0;
current_entry_ = nullptr;
current_entry_size_ = 0;
}
void PlaylistView::focus() {
button_open.focus();
}
void PlaylistView::file_error(std::string error_message) {
nav_.display_modal("Error", "Error for \n" + file_path.string() + "\n" + error_message);
void PlaylistView::show_file_error(const fs::path& path, const std::string& message) {
nav_.display_modal("Error", "Error opening file \n" + path.string() + "\n" + message);
}
bool PlaylistView::is_active() const {
return (bool)replay_thread;
return replay_thread_ != nullptr;
}
bool PlaylistView::loop() const {
return (bool)playlist_db.size();
return check_loop.value();
}
bool PlaylistView::is_done() const {
return current_track_ >= playlist_db_.size();
}
void PlaylistView::toggle() {
if (is_active()) {
stop(false);
total_tracks = 0;
track_number = 0;
playlist_db.clear();
playlist_masterdb.clear();
} else {
total_tracks = 0;
track_number = 0;
playlist_db.clear();
playlist_masterdb.clear();
load_file(now_play_list_file);
if (!playlist_db.empty()) {
start();
}
}
if (is_active())
stop();
else
start();
}
void PlaylistView::start() {
stop(false);
reset();
playlist_entry item = playlist_db.front();
playlist_db.pop_front();
// playlist_entry item = playlist_db[0];
// for (playlist_entry item : playlist_db) {
// file_path = item.replay_file;
// rf::Frequency replay_frequency = strtoll(item.replay_frequency.c_str(),nullptr,10);
on_file_changed(item.replay_file, item.replay_frequency, item.sample_rate);
on_target_frequency_changed(item.replay_frequency);
if (playlist_db_.empty())
return; // Nothing to do.
std::unique_ptr<stream::Reader> reader;
if (next_track())
send_current_track();
}
auto p = std::make_unique<FileReader>();
auto open_error = p->open(file_path);
if (open_error.is_valid()) {
file_error("Illegal grammar");
return; // Fixes TX bug if there's a file error
} else {
reader = std::move(p);
/* Advance to the next track in the playlist. */
bool PlaylistView::next_track() {
if (is_done()) {
if (loop())
current_track_ = 0;
else
return false; // All done.
}
current_entry_ = &playlist_db_[current_track_];
current_track_++;
return true;
}
/* Transmits the current_entry_ */
void PlaylistView::send_current_track() {
replay_thread_.reset();
ready_signal_ = false;
if (!current_entry_)
return;
// Open the sample file to send.
auto reader = std::make_unique<FileReader>();
auto error = reader->open(current_entry_->replay_file);
if (error) {
show_file_error(current_entry_->replay_file, "Can't open file to send.");
return;
}
if (reader) {
button_play.set_bitmap(&bitmap_stop);
baseband::set_sample_rate(sample_rate * 8);
// Get the sample file size for the progress bar.
current_entry_size_ = reader->file().size();
progressbar_transmit.set_value(0);
replay_thread = std::make_unique<ReplayThread>(
std::move(reader),
read_size, buffer_count,
&ready_signal,
[](uint32_t return_code) {
ReplayThreadDoneMessage message{return_code};
EventDispatcher::send_message(message);
});
}
// Wait a bit before sending if specified.
// TODO: this pauses the main thread, move into ReplayThread instead.
if (current_entry_->initial_delay > 0)
chThdSleepMilliseconds(current_entry_->initial_delay);
transmitter_model.set_sampling_rate(sample_rate * 8);
// ReplayThread starts immediately on contruction so
// these need to be set before creating the ReplayThread.
transmitter_model.set_target_frequency(current_entry_->replay_frequency);
transmitter_model.set_sampling_rate(current_entry_->sample_rate * 8);
transmitter_model.set_baseband_bandwidth(baseband_bandwidth);
transmitter_model.enable();
// Use the ReplayThread class to send the data.
replay_thread_ = std::make_unique<ReplayThread>(
std::move(reader),
/* read_size */ 0x4000,
/* buffer_count */ 3,
&ready_signal_,
[](uint32_t return_code) {
ReplayThreadDoneMessage message{return_code};
EventDispatcher::send_message(message);
});
// Now it's sending, update the UI.
update_ui();
}
void PlaylistView::stop(const bool do_loop) {
if (is_active()) {
replay_thread.reset();
}
// TODO: the logic here could be more beautiful but maybe they are all same for compiler anyway....
// Notes of the logic here in case if it needed to be changed in the future:
// 1. check_loop.value() is for the LOOP checkbox
// 2. do_loop is a part of the replay thread, not a user - control thing.
// 3. when (total_tracks > track_number) is true, it means that the current track is not the last track.
// Thus, (do_loop && (total_tracks != track_number)) is for the case when the start() func were called with true AND not the last track.
// Which means it do loop until the last track.
if (check_loop.value()) {
if (do_loop) {
if (playlist_db.size() > 0) {
start();
} else {
playlist_db = playlist_masterdb;
start();
}
} else {
transmitter_model.disable();
button_play.set_bitmap(&bitmap_play);
}
} else if (!check_loop.value()) {
if (do_loop && (total_tracks > track_number)) {
if (playlist_db.size() > 0) {
start();
} else {
playlist_db = playlist_masterdb;
start();
}
} else {
transmitter_model.disable();
button_play.set_bitmap(&bitmap_play);
}
}
ready_signal = false;
void PlaylistView::stop() {
// This terminates the underlying chThread.
replay_thread_.reset();
transmitter_model.disable();
update_ui();
}
void PlaylistView::handle_replay_thread_done(const uint32_t return_code) {
void PlaylistView::update_ui() {
if (playlist_db_.empty()) {
text_track.set("Open a playlist file.");
} else {
text_track.set(
to_string_dec_uint(current_track_) + "/" +
to_string_dec_uint(playlist_db_.size()) + " " +
playlist_path_.filename().string());
}
button_play.set_bitmap(is_active() ? &bitmap_stop : &bitmap_play);
progressbar_track.set_value(current_track_);
progressbar_track.set_max(playlist_db_.size());
progressbar_transmit.set_max(current_entry_size_);
if (current_entry_) {
auto duration = ms_duration(current_entry_size_, current_entry_->sample_rate, 4);
text_filename.set(truncate(current_entry_->replay_file.filename().string(), 12));
text_sample_rate.set(unit_auto_scale(current_entry_->sample_rate, 3, 0) + "Hz");
text_duration.set(to_string_time_ms(duration));
text_frequency.set(to_string_short_freq(current_entry_->replay_frequency));
} else {
text_filename.set("-");
text_sample_rate.set("-");
text_duration.set("-");
text_frequency.set("-");
}
}
void PlaylistView::on_tx_progress(uint32_t progress) {
progressbar_transmit.set_value(progress);
}
void PlaylistView::handle_replay_thread_done(uint32_t return_code) {
if (return_code == ReplayThread::END_OF_FILE) {
stop(true);
} else if (return_code == ReplayThread::READ_ERROR) {
stop(false);
file_error("Replay thread read error");
if (next_track()) {
send_current_track();
return;
}
}
progressbar.set_value(0);
if (return_code == ReplayThread::READ_ERROR)
show_file_error(current_entry_->replay_file, "Replay read failed.");
stop();
}
PlaylistView::PlaylistView(
@@ -263,43 +252,30 @@ PlaylistView::PlaylistView(
&text_filename,
&text_sample_rate,
&text_duration,
&progressbar,
&field_frequency,
&tx_view, // this handles now the previous rfgain, rfamp
&progressbar_track,
&progressbar_transmit,
&text_frequency,
&tx_view,
&check_loop,
&button_play,
// &text_track,
// TODO: add track number
&text_track,
&waterfall,
});
field_frequency.set_value(target_frequency());
field_frequency.set_step(receiver_model.frequency_step());
field_frequency.on_change = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
this->field_frequency.set_value(f);
};
};
field_frequency.set_step(5000);
waterfall.show_audio_spectrum_view(false);
button_play.on_select = [this](ImageButton&) {
this->toggle();
toggle();
};
button_open.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".PPL");
open_view->on_changed = [this](std::filesystem::path new_file_path) {
now_play_list_file = new_file_path;
load_file(new_file_path);
on_file_changed(new_file_path);
};
};
update_ui();
}
PlaylistView::~PlaylistView() {
@@ -307,33 +283,23 @@ PlaylistView::~PlaylistView() {
baseband::shutdown();
}
void PlaylistView::set_parent_rect(Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
const ui::Rect waterfall_rect{
0, header_height, new_parent_rect.width(),
new_parent_rect.height() - header_height};
waterfall.set_parent_rect(waterfall_rect);
}
void PlaylistView::on_hide() {
stop(false);
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
// it's being shown or hidden.
stop();
waterfall.on_hide();
View::on_hide();
}
void PlaylistView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
const ui::Rect waterfall_rect{0, header_height, new_parent_rect.width(),
new_parent_rect.height() - header_height};
waterfall.set_parent_rect(waterfall_rect);
}
void PlaylistView::on_target_frequency_changed(rf::Frequency f) {
set_target_frequency(f);
}
void PlaylistView::set_target_frequency(const rf::Frequency new_value) {
persistent_memory::set_tuned_frequency(new_value);
;
}
rf::Frequency PlaylistView::target_frequency() const {
return persistent_memory::tuned_frequency();
void PlaylistView::focus() {
button_open.focus();
}
} /* namespace ui */
+73 -64
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed, zxkmm
*
* This file is part of PortaPack.
*
@@ -23,101 +24,109 @@
#define SHORT_UI true
#define NORMAL_UI false
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "replay_thread.hpp"
#include "ui_spectrum.hpp"
#include "ui_transmitter.hpp"
#include <string>
#include <memory>
#include <deque>
#include "ui_transmitter.hpp"
#include <vector>
namespace ui {
class PlaylistView : public View {
public:
PlaylistView(NavigationView& nav);
~PlaylistView();
// Disable copy to make -Weffc++ happy.
PlaylistView(const PlaylistView&) = delete;
PlaylistView& operator=(const PlaylistView&) = delete;
void set_parent_rect(Rect new_parent_rect) override;
void on_hide() override;
void set_parent_rect(const Rect new_parent_rect) override;
void focus() override;
std::string title() const override { return "Playlist"; };
private:
NavigationView& nav_;
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_playlist", app_settings::Mode::TX};
static constexpr ui::Dim header_height = 3 * 16;
// More header == less spectrum view.
static constexpr ui::Dim header_height = 4 * 16;
static constexpr uint32_t baseband_bandwidth = 2500000;
struct playlist_entry {
rf::Frequency replay_frequency{0};
std::string replay_file{};
std::filesystem::path replay_file{};
uint32_t sample_rate{};
uint32_t next_delay{};
uint32_t initial_delay{};
};
std::deque<playlist_entry> playlist_db{};
std::deque<playlist_entry> playlist_masterdb{};
uint32_t sample_rate = 0;
int32_t tx_gain{47};
bool rf_amp{true}; // aux private var to store temporal, Replay App rf_amp user selection.
static constexpr uint32_t baseband_bandwidth = 2500000;
const size_t read_size{16384};
const size_t buffer_count{3};
void load_file(std::filesystem::path playlist_path);
void txtline_process(std::string&);
void on_file_changed(std::filesystem::path new_file_path, rf::Frequency replay_frequency, uint32_t replay_sample_rate);
void on_target_frequency_changed(rf::Frequency f);
void on_tx_progress(const uint32_t progress);
void set_target_frequency(const rf::Frequency new_value);
rf::Frequency target_frequency() const;
void toggle();
void start();
void stop(const bool do_loop);
std::unique_ptr<ReplayThread> replay_thread_{};
bool ready_signal_{}; // Used to signal the ReplayThread.
size_t current_track_{0};
const playlist_entry* current_entry_{};
size_t current_entry_size_{0};
std::vector<playlist_entry> playlist_db_{};
std::filesystem::path playlist_path_{};
void load_file(const std::filesystem::path& path);
void on_file_changed(const std::filesystem::path& path);
void reset();
void show_file_error(
const std::filesystem::path& path,
const std::string& message);
bool is_active() const;
bool loop() const;
void set_ready();
void handle_replay_thread_done(const uint32_t return_code);
void file_error(std::string error_message);
bool is_done() const;
std::filesystem::path file_path{};
std::unique_ptr<ReplayThread> replay_thread{};
bool ready_signal{false};
size_t track_number{0};
size_t total_tracks{0};
std::filesystem::path now_play_list_file{};
void toggle();
void start();
bool next_track();
void send_current_track();
void stop();
void update_ui();
/* There are called by Message handlers. */
void on_tx_progress(uint32_t progress);
void handle_replay_thread_done(uint32_t return_code);
Button button_open{
{0 * 8, 0 * 16, 10 * 8, 2 * 16},
"Open file"};
"Open PPL"};
Text text_filename{
{11 * 8, 0 * 16, 12 * 8, 16},
"-"};
{11 * 8, 0 * 16, 12 * 8, 16}};
Text text_sample_rate{
{24 * 8, 0 * 16, 6 * 8, 16},
"-"};
{24 * 8, 0 * 16, 6 * 8, 16}};
Text text_duration{
{11 * 8, 1 * 16, 6 * 8, 16},
"-"};
ProgressBar progressbar{
{18 * 8, 1 * 16, 12 * 8, 16}};
{11 * 8, 1 * 16, 6 * 8, 16}};
FrequencyField field_frequency{
{0 * 8, 2 * 16},
};
ProgressBar progressbar_track{
{18 * 8, 1 * 16, 12 * 8, 8}};
ProgressBar progressbar_transmit{
{18 * 8, 3 * 8, 12 * 8, 8}};
Text text_frequency{
{0 * 8, 2 * 16, 9 * 8, 16}};
TransmitterView2 tx_view{
// new handling of NumberField field_rfgain, NumberField field_rfamp
74, 1 * 8, SHORT_UI // x(columns), y (line) position. (Used in Repay / GPS Simul / Play list App)
// 10*8, 2*8, NORMAL_UI // x(columns), y (line) position. (Used in Mic App)
74, 1 * 8, SHORT_UI // x(columns), y (line) position.
};
Checkbox check_loop{
@@ -125,39 +134,39 @@ class PlaylistView : public View {
4,
"Loop",
true};
ImageButton button_play{
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
&bitmap_play,
Color::green(),
Color::black()};
// TODO: add track number
// Text text_track{
// {18 * 8, 1 * 16, 12 * 8, 16},
// "0/0"};
Text text_track{
{0 * 8, 3 * 16, 30 * 8, 16}};
spectrum::WaterfallWidget waterfall{};
MessageHandlerRegistration message_handler_replay_thread_error{
Message::ID::ReplayThreadDone,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
this->handle_replay_thread_done(message.return_code);
[this](const Message* p) {
auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
handle_replay_thread_done(message.return_code);
}};
MessageHandlerRegistration message_handler_fifo_signal{
Message::ID::RequestSignal,
[this](const Message* const p) {
const auto message = static_cast<const RequestSignalMessage*>(p);
[this](const Message* p) {
auto message = static_cast<const RequestSignalMessage*>(p);
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
this->set_ready();
ready_signal_ = true;
}
}};
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.progress);
[this](const Message* p) {
auto message = *reinterpret_cast<const TXProgressMessage*>(p);
on_tx_progress(message.progress);
}};
};
+3 -20
View File
@@ -23,7 +23,6 @@
#include "ui_pocsag_tx.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "string_format.hpp"
#include "ui_textentry.hpp"
@@ -39,13 +38,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void POCSAGTXView::on_tx_progress(const uint32_t progress, const bool done) {
@@ -85,11 +79,9 @@ bool POCSAGTXView::start_tx() {
progressbar.set_max(total_frames);
transmitter_model.set_sampling_rate(2280000);
transmitter_model.set_rf_amp(true);
transmitter_model.set_lna(40);
transmitter_model.set_vga(40);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
uint8_t* data_ptr = shared_memory.bb_data.data;
@@ -143,15 +135,6 @@ POCSAGTXView::POCSAGTXView(
&progressbar,
&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
@@ -172,9 +155,9 @@ POCSAGTXView::POCSAGTXView(
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+8 -4
View File
@@ -32,6 +32,7 @@
#include "message.hpp"
#include "transmitter_model.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "pocsag.hpp"
using namespace pocsag;
@@ -58,6 +59,13 @@ class POCSAGTXView : public View {
std::string message{};
NavigationView& nav_;
TxRadioState radio_state_{
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_pocsag", app_settings::Mode::TX};
BCHCode BCH_code{
{1, 0, 1, 0, 0, 1},
5,
@@ -65,10 +73,6 @@ class POCSAGTXView : public View {
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();
+3 -19
View File
@@ -24,7 +24,6 @@
#include "portapack.hpp"
#include "baseband_api.hpp"
#include "cpld_update.hpp"
#include "portapack_shared_memory.hpp"
#include <cstring>
@@ -160,13 +159,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void RDSView::start_tx() {
@@ -193,8 +187,6 @@ void RDSView::start_tx() {
else
frame_datetime.clear();
transmitter_model.set_sampling_rate(2280000U);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
tx_thread = std::make_unique<RDSThread>(frames);
@@ -218,14 +210,6 @@ RDSView::RDSView(
&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);
@@ -239,9 +223,9 @@ RDSView::RDSView(
options_pty.set_selected_index(0); // None
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+7 -3
View File
@@ -25,6 +25,7 @@
#include "ui_textentry.hpp"
#include "ui_tabview.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "rds.hpp"
using namespace rds;
@@ -140,9 +141,12 @@ class RDSView : public View {
NavigationView& nav_;
RDS_flags rds_flags{};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
TxRadioState radio_state_{
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_rds", app_settings::Mode::TX};
std::vector<RDSGroup> frame_psn{};
std::vector<RDSGroup> frame_radiotext{};
+73 -85
View File
@@ -30,6 +30,12 @@ using portapack::memory::map::backup_ram;
namespace ui {
void ReconView::set_loop_config(bool v) {
continuous = v;
button_loop_config.set_style(v ? &Styles::green : &Styles::white);
persistent_memory::set_recon_continuous(continuous);
}
void ReconView::clear_freqlist_for_ui_action() {
audio::output::stop();
// flag to detect and reload frequency_list
@@ -93,9 +99,9 @@ bool ReconView::recon_save_freq(const std::string& freq_file_path, size_t freq_i
auto result = recon_file.open(freq_file_path); // First recon if freq is already in txt
if (!result.is_valid()) {
char one_char[1]; // Read it char by char
std::string line; // and put read line in here
bool found = false;
char one_char[1]{}; // Read it char by char
std::string line{}; // and put read line in here
bool found{false};
for (size_t pointer = 0; pointer < recon_file.size(); pointer++) {
recon_file.seek(pointer);
recon_file.read(one_char, 1);
@@ -128,16 +134,16 @@ bool ReconView::recon_save_freq(const std::string& freq_file_path, size_t freq_i
}
bool ReconView::recon_load_config_from_sd() {
File settings_file;
size_t length, file_position = 0;
char* pos;
char* line_start;
char* line_end;
char file_data[257];
uint32_t it = 0;
uint32_t nb_params = RECON_SETTINGS_NB_PARAMS;
std::string params[RECON_SETTINGS_NB_PARAMS];
File settings_file{};
size_t length{0};
size_t file_position{0};
char* pos{NULL};
char* line_start{NULL};
char* line_end{NULL};
char file_data[257]{};
uint32_t it{0};
uint32_t nb_params{RECON_SETTINGS_NB_PARAMS};
std::string params[RECON_SETTINGS_NB_PARAMS]{};
make_new_directory(u"SETTINGS");
@@ -291,29 +297,18 @@ void ReconView::recon_redraw() {
void ReconView::handle_retune() {
if (last_freq != freq) {
last_freq = freq;
receiver_model.set_tuning_frequency(freq); // Retune
receiver_model.set_target_frequency(freq); // Retune
}
if (frequency_list.size() > 0) {
if (last_entry.modulation != frequency_list[current_index].modulation && frequency_list[current_index].modulation >= 0) {
last_entry.modulation = frequency_list[current_index].modulation;
field_mode.set_selected_index(frequency_list[current_index].modulation);
last_entry.bandwidth = -1;
}
// Set bandwidth if any
if (last_entry.bandwidth != frequency_list[current_index].bandwidth && frequency_list[current_index].bandwidth >= 0) {
last_entry.bandwidth = frequency_list[current_index].bandwidth;
switch (frequency_list[current_index].modulation) {
case AM_MODULATION:
receiver_model.set_am_configuration(freq);
break;
case NFM_MODULATION:
receiver_model.set_nbfm_configuration(freq);
break;
case WFM_MODULATION:
receiver_model.set_wfm_configuration(freq);
default:
break;
}
field_bw.set_selected_index(freq);
field_bw.set_selected_index(frequency_list[current_index].bandwidth);
}
if (last_entry.step != frequency_list[current_index].step && frequency_list[current_index].step >= 0) {
last_entry.step = frequency_list[current_index].step;
@@ -361,10 +356,8 @@ void ReconView::focus() {
}
ReconView::~ReconView() {
// save app config
// Save recon config.
recon_save_config_to_sd();
// save app common settings
settings.save("recon", &app_settings);
audio::output::stop();
receiver_model.disable();
@@ -380,11 +373,12 @@ ReconView::ReconView(NavigationView& nav)
&field_volume,
&field_bw,
&field_squelch,
&field_nblocks,
&field_wait,
&field_lock_wait,
&button_config,
&button_scanner_mode,
&button_looking_glass,
&button_loop_config,
&file_name,
&rssi,
&text_cycle,
@@ -399,6 +393,7 @@ ReconView::ReconView(NavigationView& nav)
&button_manual_end,
&button_manual_recon,
&field_mode,
&field_recon_match_mode,
&step_mode,
&button_pause,
&button_audio_app,
@@ -410,8 +405,7 @@ ReconView::ReconView(NavigationView& nav)
def_step = 0;
// HELPER: Pre-setting a manual range, based on stored frequency
rf::Frequency stored_freq = persistent_memory::tuned_frequency();
receiver_model.set_tuning_frequency(stored_freq);
rf::Frequency stored_freq = receiver_model.target_frequency();
if (stored_freq - OneMHz > 0)
frequency_range.min = stored_freq - OneMHz;
else
@@ -422,6 +416,7 @@ ReconView::ReconView(NavigationView& nav)
else
frequency_range.max = MAX_UFREQ;
button_manual_end.set_text(to_string_short_freq(frequency_range.max));
// Loading settings
autostart = persistent_memory::recon_autostart_recon();
autosave = persistent_memory::recon_autosave_freqs();
@@ -431,16 +426,6 @@ ReconView::ReconView(NavigationView& nav)
load_ranges = persistent_memory::recon_load_ranges();
load_hamradios = persistent_memory::recon_load_hamradios();
update_ranges = persistent_memory::recon_update_ranges_when_recon();
if (sd_card_mounted) {
// load auto common app settings
auto rc = settings.load("recon", &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);
receiver_model.set_rf_amp(app_settings.rx_amp);
}
}
button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) {
clear_freqlist_for_ui_action();
@@ -530,8 +515,10 @@ ReconView::ReconView(NavigationView& nav)
} else {
if (!recon) {
recon_resume();
user_pause = false;
} else {
recon_pause();
user_pause = true;
}
}
}
@@ -547,10 +534,10 @@ ReconView::ReconView(NavigationView& nav)
nav_.push<AnalogAudioView>();
};
button_looking_glass.on_select = [this](Button&) {
nav_.pop();
nav_.push<GlassView>();
button_loop_config.on_select = [this](Button&) {
set_loop_config(!continuous);
};
set_loop_config(continuous);
rssi.set_focusable(true);
rssi.set_peak(true, 500);
@@ -559,17 +546,18 @@ ReconView::ReconView(NavigationView& nav)
nav_.push<LevelView>();
};
// TODO: *BUG* Both transmitter_model and receiver_model share the same pmem setting for target_frequency.
button_mic_app.on_select = [this](Button&) {
if (frequency_list.size() > 0 && current_index >= 0 && (unsigned)current_index < frequency_list.size()) {
if (frequency_list[current_index].type == HAMRADIO) {
// if it's a HAMRADIO entry, then frequency_a is the freq at which the repeater reveive, so we have to set it in transmit in mic app
transmitter_model.set_tuning_frequency(frequency_list[current_index].frequency_a);
transmitter_model.set_target_frequency(frequency_list[current_index].frequency_a);
// if it's a HAMRADIO entry, then frequency_b is the freq at which the repeater transmit, so we have to set it in receive in mic app
receiver_model.set_tuning_frequency(frequency_list[current_index].frequency_b);
receiver_model.set_target_frequency(frequency_list[current_index].frequency_b);
} else {
// it's single or range so we us actual tuned frequency
transmitter_model.set_tuning_frequency(freq);
receiver_model.set_tuning_frequency(freq);
transmitter_model.set_target_frequency(freq);
receiver_model.set_target_frequency(freq);
}
}
// there is no way yet to set modulation and bandwidth from Recon to MicApp
@@ -610,7 +598,7 @@ ReconView::ReconView(NavigationView& nav)
}
// also remove from output file if in scanner mode
if (scanner_mode) {
File freqman_file;
File freqman_file{};
delete_file(freq_file_path);
auto result = freqman_file.create(freq_file_path);
if (!result.is_valid()) {
@@ -623,10 +611,10 @@ ReconView::ReconView(NavigationView& nav)
}
} else if (manual_mode) // only remove from output
{
File recon_file;
File tmp_recon_file;
std::string tmp_freq_file_path = freq_file_path + ".TMP";
std::string frequency_to_add;
File recon_file{};
File tmp_recon_file{};
std::string tmp_freq_file_path{freq_file_path + ".TMP"};
std::string frequency_to_add{};
freqman_entry entry = frequency_list[current_index];
entry.frequency_a = freq;
@@ -643,8 +631,8 @@ ReconView::ReconView(NavigationView& nav)
bool found = false;
result = recon_file.open(freq_file_path); // First recon if freq is already in txt
if (!result.is_valid()) {
char one_char[1]; // Read it char by char
std::string line; // and put read line in here
char one_char[1]{}; // Read it char by char
std::string line{}; // and put read line in here
for (size_t pointer = 0; pointer < recon_file.size(); pointer++) {
recon_file.seek(pointer);
recon_file.read(one_char, 1);
@@ -668,7 +656,7 @@ ReconView::ReconView(NavigationView& nav)
}
}
}
receiver_model.set_tuning_frequency(frequency_list[current_index].frequency_a); // retune
receiver_model.set_target_frequency(frequency_list[current_index].frequency_a); // retune
}
if (frequency_list.size() == 0) {
text_cycle.set_text(" ");
@@ -812,30 +800,22 @@ ReconView::ReconView(NavigationView& nav)
button_config.on_select = [this, &nav](Button&) {
clear_freqlist_for_ui_action();
auto open_view = nav.push<ReconSetupView>(input_file, output_file, recon_lock_duration, recon_lock_nb_match, recon_match_mode);
auto open_view = nav.push<ReconSetupView>(input_file, output_file);
open_view->on_changed = [this](std::vector<std::string> result) {
freqlist_cleared_for_ui_action = false;
input_file = result[0];
output_file = result[1];
freq_file_path = "/FREQMAN/" + output_file + ".TXT";
recon_lock_duration = strtol(result[2].c_str(), nullptr, 10);
recon_lock_nb_match = strtol(result[3].c_str(), nullptr, 10);
recon_match_mode = strtol(result[4].c_str(), nullptr, 10);
recon_save_config_to_sd();
autosave = persistent_memory::recon_autosave_freqs();
autostart = persistent_memory::recon_autostart_recon();
continuous = persistent_memory::recon_continuous();
filedelete = persistent_memory::recon_clear_output();
load_freqs = persistent_memory::recon_load_freqs();
load_ranges = persistent_memory::recon_load_ranges();
load_hamradios = persistent_memory::recon_load_hamradios();
update_ranges = persistent_memory::recon_update_ranges_when_recon();
field_wait.set_value(wait);
field_lock_wait.set_value(recon_lock_duration);
colorize_waits();
frequency_file_load(false);
if (autostart) {
@@ -846,11 +826,23 @@ ReconView::ReconView(NavigationView& nav)
};
};
field_recon_match_mode.on_change = [this](size_t, OptionsField::value_t v) {
recon_match_mode = v;
colorize_waits();
};
field_wait.on_change = [this](int32_t v) {
wait = v;
colorize_waits();
};
field_nblocks.on_change = [this](int32_t v) {
recon_lock_nb_match = v;
if ((unsigned)v < freq_lock)
freq_lock = v;
colorize_waits();
};
field_lock_wait.on_change = [this](uint32_t v) {
recon_lock_duration = v;
colorize_waits();
@@ -869,9 +861,11 @@ ReconView::ReconView(NavigationView& nav)
recon_load_config_from_sd();
freq_file_path = "/FREQMAN/" + output_file + ".TXT";
field_recon_match_mode.set_selected_index(recon_match_mode);
field_squelch.set_value(squelch);
field_wait.set_value(wait);
field_lock_wait.set_value(recon_lock_duration);
field_nblocks.set_value(recon_lock_nb_match);
colorize_waits();
// fill modulation and step options
@@ -879,9 +873,8 @@ ReconView::ReconView(NavigationView& nav)
freqman_set_step_option(step_mode);
// set radio
change_mode(AM_MODULATION); // start on AM.
field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency()); // first tune
change_mode(AM_MODULATION); // start on AM.
field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector
if (filedelete) {
delete_file(freq_file_path);
@@ -922,7 +915,7 @@ void ReconView::frequency_file_load(bool stop_all_before) {
desc_cycle.set(" NO " + file_input + ".TXT FILE ...");
file_name.set("=> NO DATA");
} else {
file_name.set("=> " + file_input);
file_name.set(file_input + "=>" + output_file);
if (frequency_list.size() == 0) {
file_name.set_style(&Styles::red);
desc_cycle.set_style(&Styles::red);
@@ -1010,7 +1003,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
if (!manual_mode) {
frequency_file_load(false);
}
if (autostart) {
if (autostart && !user_pause) {
recon_resume();
} else {
recon_pause();
@@ -1073,7 +1066,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
text_timer.set("TIMER: " + to_string_dec_int(timer));
}
if (timer) {
if (!continuous_lock)
if (!continuous_lock || recon_match_mode == RECON_MATCH_SPARSE)
timer -= STATS_UPDATE_INTERVAL;
if (timer < 0) {
timer = 0;
@@ -1303,9 +1296,7 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
receiver_model.set_am_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
text_ctcss.set(" ");
break;
case NFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
@@ -1315,8 +1306,6 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.set_nbfm_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
break;
case WFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
@@ -1326,9 +1315,7 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.set_wfm_configuration(field_bw.selected_index_value());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
text_ctcss.set(" ");
text_ctcss.set(" ");
break;
default:
break;
@@ -1348,12 +1335,13 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
}
void ReconView::handle_coded_squelch(const uint32_t value) {
float diff, min_diff = value;
float diff{0.0};
float min_diff{(float)value};
size_t min_idx{0};
size_t c;
size_t c{0};
if (field_mode.selected_index() != NFM_MODULATION) {
text_ctcss.set(" ");
text_ctcss.set(" ");
return;
}
@@ -1372,7 +1360,7 @@ void ReconView::handle_coded_squelch(const uint32_t value) {
if (min_diff < 40)
text_ctcss.set("T: " + tone_keys[min_idx].first);
else
text_ctcss.set(" ");
text_ctcss.set(" ");
}
}
} /* namespace ui */
+128 -109
View File
@@ -39,6 +39,7 @@
#include "string_format.hpp"
#include "file.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_recon_settings.hpp"
namespace ui {
@@ -60,6 +61,11 @@ class ReconView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_recon", app_settings::Mode::RX};
void set_loop_config(bool v);
void clear_freqlist_for_ui_action();
void reset_indexes();
void audio_output_start();
@@ -79,69 +85,70 @@ class ReconView : public View {
bool recon_load_config_from_sd();
bool recon_save_config_to_sd();
bool recon_save_freq(const std::string& freq_file_path, size_t index, bool warn_if_exists);
jammer::jammer_range_t frequency_range{false, 0, MAX_UFREQ}; // perfect for manual recon task too...
int32_t squelch{0};
int32_t db{0};
int32_t timer{0};
int32_t wait{RECON_DEF_WAIT_DURATION}; // in msec. if > 0 wait duration after a lock, if < 0 duration is set to 'wait' unless there is no more activity
freqman_db frequency_list = {};
freqman_db frequency_list{};
int32_t current_index{0};
bool continuous_lock{false};
bool freqlist_cleared_for_ui_action{false}; // flag positioned by ui widgets to manage freqlist unload/load
std::string input_file = {"RECON"};
std::string output_file = {"RECON_RESULTS"};
std::string description = {"...no description..."};
bool autosave = {true};
bool autostart = {true};
bool continuous = {true};
bool filedelete = {true};
bool load_freqs = {true};
bool load_ranges = {true};
bool load_hamradios = {true};
bool update_ranges = {true};
bool fwd = {true};
bool recon = true;
uint32_t recon_lock_nb_match = {3};
uint32_t recon_lock_duration = {RECON_MIN_LOCK_DURATION};
uint32_t recon_match_mode = {RECON_MATCH_CONTINUOUS};
std::string input_file{"RECON"};
std::string output_file{"RECON_RESULTS"};
std::string description{"...no description..."};
bool autosave{true};
bool autostart{true};
bool continuous{true};
bool filedelete{true};
bool load_freqs{true};
bool load_ranges{true};
bool load_hamradios{true};
bool update_ranges{true};
bool fwd{true};
bool recon{true};
bool user_pause{false};
uint32_t recon_lock_nb_match{3};
uint32_t recon_lock_duration{RECON_MIN_LOCK_DURATION};
uint32_t recon_match_mode{RECON_MATCH_CONTINUOUS};
bool scanner_mode{false};
bool manual_mode{false};
bool sd_card_mounted = false;
int32_t stepper = 0;
int32_t index_stepper = 0;
int64_t freq = 0;
uint32_t step = 0;
freqman_index_t def_modulation = 0;
freqman_index_t def_bandwidth = 0;
freqman_index_t def_step = 0;
tone_index tone = 0;
freqman_entry last_entry = {};
bool entry_has_changed = false;
bool sd_card_mounted{false};
int32_t stepper{0};
int32_t index_stepper{0};
int64_t freq{0};
uint32_t step{0};
freqman_index_t def_modulation{0};
freqman_index_t def_bandwidth{0};
freqman_index_t def_step{0};
tone_index tone{0};
freqman_entry last_entry{};
bool entry_has_changed{false};
uint32_t freq_lock{0};
int64_t minfreq = 0;
int64_t maxfreq = 0;
bool has_looped = false;
int8_t status = -1; // 0 recon , 1 locking , 2 locked
int32_t last_timer = -1;
int8_t last_db = -127;
uint16_t last_nb_match = 999;
uint16_t last_freq_lock = 999;
size_t last_list_size = 0;
int8_t last_rssi_min = -127;
int8_t last_rssi_med = -127;
int8_t last_rssi_max = -127;
int32_t last_index = -1;
int32_t last_squelch_index = -1;
int64_t last_freq = 0;
std::string freq_file_path = {};
int64_t minfreq{0};
int64_t maxfreq{0};
bool has_looped{false};
int8_t status{-1}; // 0 recon , 1 locking , 2 locked
int32_t last_timer{-1};
int8_t last_db{-127};
uint16_t last_nb_match{999};
uint16_t last_freq_lock{999};
size_t last_list_size{0};
int8_t last_rssi_min{-127};
int8_t last_rssi_med{-127};
int8_t last_rssi_max{-127};
int32_t last_index{-1};
int32_t last_squelch_index{-1};
int64_t last_freq{0};
std::string freq_file_path{};
Labels labels{
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()},
{{0 * 8, 1 * 16}, "BW: SQ: W,L: , ", Color::light_grey()},
{{3 * 8, 10 * 16}, "START END MANUAL", Color::light_grey()},
{{0 * 8, (26 * 8) + 4}, "MODE:", Color::light_grey()},
{{11 * 8, (26 * 8) + 4}, "STEP:", Color::light_grey()},
};
{{3 * 8, 8 * 16}, "START END", Color::light_grey()},
{{0 * 8, (22 * 8)}, " S: ", Color::light_grey()},
{{0 * 8, (24 * 8) + 4}, "NBLCKS:x W,L: , ", Color::light_grey()},
{{0 * 8, (26 * 8) + 4}, "MODE: , SQUELCH: ", Color::light_grey()}};
LNAGainField field_lna{
{4 * 8, 0 * 16}};
@@ -155,65 +162,41 @@ class ReconView : public View {
AudioVolumeField field_volume{
{24 * 8, 0 * 16}};
OptionsField field_bw{
{3 * 8, 1 * 16},
6,
{}};
NumberField field_squelch{
{12 * 8, 1 * 16},
3,
{-90, 20},
1,
' ',
Text file_name{
// show file used
{0, 1 * 16, SCREEN_W, 16},
};
NumberField field_wait{
{20 * 8, 1 * 16},
5,
{-RECON_MAX_LOCK_DURATION, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
};
NumberField field_lock_wait{
{26 * 8, 1 * 16},
4,
{RECON_MIN_LOCK_DURATION, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
Text desc_cycle{
{0, 2 * 16, SCREEN_W, 16},
};
RSSI rssi{
{0 * 16, 2 * 16, SCREEN_W - 8 * 8 + 4, 14},
{0 * 16, 3 * 16 + 2, SCREEN_W - 8 * 8 + 4, 12},
};
ButtonWithEncoder text_cycle{
{0, 3 * 16, 4 * 8, 16},
{0, 4 * 16, 4 * 8, 16},
""};
// "/XXX -XXX db" => 12 chars max
Text text_max{
{4 * 8, 3 * 16, 12 * 8, 16},
{4 * 8, 4 * 16, 12 * 8, 16},
};
// "XX/XX" => 5 chars max
Text text_nb_locks{
{16 * 8, 3 * 16, 5 * 8, 16},
};
Text desc_cycle{
{0, 4 * 16, SCREEN_W, 16},
{16 * 8, 4 * 16, 5 * 8, 16},
};
Text big_display{
// Show frequency in text mode
{0, 5 * 16, 23 * 8, 16},
{0, 5 * 16, 21 * 8, 16},
};
Text freq_stats{
// Show frequency stats in text mode
{0, 6 * 16, 23 * 8, 16},
{0, 6 * 16, 21 * 8, 16},
};
// TIMER: 9999
@@ -224,48 +207,87 @@ class ReconView : public View {
// T: Senn. 32.000k
Text text_ctcss{
{12 * 8 + 4, 7 * 16, 14 * 8, 1 * 8},
{14 * 8, 7 * 16, 8 * 8, 1 * 8},
""};
Button button_config{
{SCREEN_W - 7 * 8, 2 * 16, 7 * 8, 28},
"CONFIG"};
Button button_looking_glass{
{SCREEN_W - 7 * 8, 5 * 16, 7 * 8, 28},
"GLASS"};
// Button can be RECON or SCANNER
Button button_scanner_mode{
{SCREEN_W - 7 * 8, 8 * 16, 7 * 8, 28},
{SCREEN_W - 7 * 8, 3 * 16, 7 * 8, 28},
"RECON"};
Text file_name{
// show file used
{0, 8 * 16 + 6, SCREEN_W - 7 * 8, 16},
};
Button button_loop_config{
{SCREEN_W - 7 * 8, 5 * 16, 7 * 8, 28},
"[LOOP]"};
Button button_config{
{SCREEN_W - 7 * 8, 7 * 16, 7 * 8, 28},
"CONFIG"};
ButtonWithEncoder button_manual_start{
{0 * 8, 11 * 16, 11 * 8, 28},
{0 * 8, 9 * 16, 11 * 8, 28},
""};
ButtonWithEncoder button_manual_end{
{12 * 8 - 6, 11 * 16, 11 * 8, 28},
{12 * 8 - 6, 9 * 16, 11 * 8, 28},
""};
OptionsField field_recon_match_mode{
{0 * 8, 11 * 16},
16, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
{
{"MATCH:CONTINOUS", 0},
{"MATCH:SPARSE", 1}}};
OptionsField step_mode{
{18 * 8, 11 * 16},
12,
{}};
Button button_manual_recon{
{23 * 8 - 3, 11 * 16, 7 * 8, 28},
{23 * 8, 9 * 16, 7 * 8, 28},
"SEARCH"};
NumberField field_nblocks{
{8 * 8, 24 * 8 + 4},
2,
{1, 99},
1,
' ',
};
NumberField field_wait{
{19 * 8, 24 * 8 + 4},
5,
{-RECON_MAX_LOCK_DURATION, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
};
NumberField field_lock_wait{
{25 * 8, 24 * 8 + 4},
4,
{RECON_MIN_LOCK_DURATION, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
};
OptionsField field_mode{
{5 * 8, (26 * 8) + 4},
{6 * 8, (26 * 8) + 4},
3,
{}};
OptionsField field_bw{
{10 * 8, (26 * 8) + 4},
6,
{}};
OptionsField step_mode{
{17 * 8, (26 * 8) + 4},
12,
{}};
NumberField field_squelch{
{26 * 8, (26 * 8) + 4},
3,
{-90, 20},
1,
' ',
};
ButtonWithEncoder button_pause{
{0, (15 * 16) - 4, 72, 28},
@@ -307,9 +329,6 @@ class ReconView : public View {
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
};
} /* namespace ui */
+10 -35
View File
@@ -44,12 +44,10 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
&button_output_file,
&checkbox_autosave_freqs,
&checkbox_autostart_recon,
&checkbox_continuous,
&checkbox_clear_output});
checkbox_autosave_freqs.set_value(persistent_memory::recon_autosave_freqs());
checkbox_autostart_recon.set_value(persistent_memory::recon_autostart_recon());
checkbox_continuous.set_value(persistent_memory::recon_continuous());
checkbox_clear_output.set_value(persistent_memory::recon_clear_output());
text_input_file.set(_input_file);
@@ -96,49 +94,35 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
void ReconSetupViewMain::save(std::string& input_file, std::string& output_file) {
persistent_memory::set_recon_autosave_freqs(checkbox_autosave_freqs.value());
persistent_memory::set_recon_autostart_recon(checkbox_autostart_recon.value());
persistent_memory::set_recon_continuous(checkbox_continuous.value());
persistent_memory::set_recon_clear_output(checkbox_clear_output.value());
input_file = _input_file;
output_file = _output_file;
};
void ReconSetupViewMore::save(uint32_t& recon_lock_duration, uint32_t& recon_lock_nb_match, uint32_t& recon_match_mode) {
void ReconSetupViewMore::save() {
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
recon_lock_duration = field_recon_lock_duration.value();
recon_lock_nb_match = field_recon_lock_nb_match.value();
recon_match_mode = field_recon_match_mode.selected_index_value();
};
void ReconSetupViewMain::focus() {
button_load_freqs.focus();
}
ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect, uint32_t recon_lock_duration, uint32_t recon_lock_nb_match, uint32_t recon_match_mode)
: View(parent_rect), _recon_lock_duration{recon_lock_duration}, _recon_lock_nb_match{recon_lock_nb_match}, _recon_match_mode{recon_match_mode} {
ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
: View(parent_rect) {
(void)nav;
hidden(true);
add_children({
&checkbox_load_freqs,
&checkbox_load_ranges,
&checkbox_load_hamradios,
&checkbox_update_ranges_when_recon,
&text_recon_lock_duration,
&field_recon_lock_duration,
&text_recon_lock_nb,
&field_recon_lock_nb_match,
&field_recon_match_mode,
});
add_children({&checkbox_load_freqs,
&checkbox_load_ranges,
&checkbox_load_hamradios,
&checkbox_update_ranges_when_recon});
checkbox_load_freqs.set_value(persistent_memory::recon_load_freqs());
checkbox_load_ranges.set_value(persistent_memory::recon_load_ranges());
checkbox_load_hamradios.set_value(persistent_memory::recon_load_hamradios());
checkbox_update_ranges_when_recon.set_value(persistent_memory::recon_update_ranges_when_recon());
field_recon_lock_duration.set_value(_recon_lock_duration);
field_recon_lock_nb_match.set_value(_recon_lock_nb_match);
field_recon_match_mode.set_by_value(_recon_match_mode);
};
void ReconSetupViewMore::focus() {
@@ -149,14 +133,8 @@ void ReconSetupView::focus() {
viewMain.focus();
}
ReconSetupView::ReconSetupView(
NavigationView& nav,
std::string _input_file,
std::string _output_file,
uint32_t _recon_lock_duration,
uint32_t _recon_lock_nb_match,
uint32_t _recon_match_mode)
: nav_{nav}, input_file{_input_file}, output_file{_output_file}, recon_lock_duration{_recon_lock_duration}, recon_lock_nb_match{_recon_lock_nb_match}, recon_match_mode{_recon_match_mode} {
ReconSetupView::ReconSetupView(NavigationView& nav, std::string _input_file, std::string _output_file)
: nav_{nav}, input_file{_input_file}, output_file{_output_file} {
add_children({&tab_view,
&viewMain,
&viewMore,
@@ -164,13 +142,10 @@ ReconSetupView::ReconSetupView(
button_save.on_select = [this, &nav](Button&) {
viewMain.save(input_file, output_file);
viewMore.save(recon_lock_duration, recon_lock_nb_match, recon_match_mode);
viewMore.save();
std::vector<std::string> messages;
messages.push_back(input_file);
messages.push_back(output_file);
messages.push_back(to_string_dec_uint(recon_lock_duration));
messages.push_back(to_string_dec_uint(recon_lock_nb_match));
messages.push_back(to_string_dec_uint(recon_match_mode));
on_changed(messages);
nav.pop();
};
+10 -53
View File
@@ -71,8 +71,8 @@ class ReconSetupViewMain : public View {
void focus() override;
private:
std::string _input_file = {"RECON"};
std::string _output_file = {"RECON_RESULTS"};
std::string _input_file{"RECON"};
std::string _output_file{"RECON_RESULTS"};
Button button_load_freqs{
{1 * 8, 12, 18 * 8, 22},
@@ -98,29 +98,21 @@ class ReconSetupViewMain : public View {
3,
"autostart recon"};
Checkbox checkbox_continuous{
{1 * 8, 11 * 16 - 4},
3,
"continuous"};
Checkbox checkbox_clear_output{
{1 * 8, 13 * 16 - 4},
{1 * 8, 11 * 16 - 4},
3,
"clear output at start"};
};
class ReconSetupViewMore : public View {
public:
ReconSetupViewMore(NavigationView& nav, Rect parent_rect, uint32_t _recon_lock_duration, uint32_t _recon_lock_nb_match, uint32_t _recon_match_mode);
ReconSetupViewMore(NavigationView& nav, Rect parent_rect);
void save(uint32_t& recon_lock_duration, uint32_t& recon_lock_nb_match, uint32_t& recon_match_mode);
void save();
void focus() override;
private:
uint32_t _recon_lock_duration = STATS_UPDATE_INTERVAL;
uint32_t _recon_lock_nb_match = RECON_DEF_NB_MATCH;
uint32_t _recon_match_mode = RECON_MATCH_CONTINUOUS;
Checkbox checkbox_load_freqs{
{1 * 8, 12},
3,
@@ -140,43 +132,11 @@ class ReconSetupViewMore : public View {
{1 * 8, 102},
3,
"auto update m-ranges"};
NumberField field_recon_lock_duration{
{1 * 8, 132}, // position X , Y
4, // number of displayed digits (even empty)
{STATS_UPDATE_INTERVAL, RECON_MAX_LOCK_DURATION}, // range of number
STATS_UPDATE_INTERVAL, // rotary encoder increment
' ', // filling character
false // can loop
};
Text text_recon_lock_duration{
{1 * 8, 132, 22 * 8, 22},
" ms (lock duration)"};
NumberField field_recon_lock_nb_match{
{1 * 8, 162},
4,
{1, 99},
1,
' ',
false};
Text text_recon_lock_nb{
{1 * 8, 162, 25 * 8, 22},
" x (nb lock to match freq)"};
OptionsField field_recon_match_mode{
{1 * 8, 192},
20, // CONTINUOUS MATCH MODE / SPARSE TIMED MATCH MODE
{
{"SQL MATCH: CONTINOUS", 0},
{"SQL MATCH: SPARSE", 1}}};
};
class ReconSetupView : public View {
public:
ReconSetupView(NavigationView& nav, std::string _input_file, std::string _output_file, uint32_t _recon_lock_duration, uint32_t _recon_lock_nb_match, uint32_t _recon_match_mode);
ReconSetupView(NavigationView& nav, std::string _input_file, std::string _output_file);
std::function<void(std::vector<std::string> messages)> on_changed{};
@@ -187,16 +147,13 @@ class ReconSetupView : public View {
private:
NavigationView& nav_;
std::string input_file = {"RECON"};
std::string output_file = {"RECON_RESULTS"};
uint32_t recon_lock_duration = STATS_UPDATE_INTERVAL;
uint32_t recon_lock_nb_match = RECON_DEF_NB_MATCH;
uint32_t recon_match_mode = RECON_MATCH_CONTINUOUS;
std::string input_file{"RECON"};
std::string output_file{"RECON_RESULTS"};
Rect view_rect = {0, 3 * 8, SCREEN_W, 230};
Rect view_rect{0, 3 * 8, SCREEN_W, 230};
ReconSetupViewMain viewMain{nav_, view_rect, input_file, output_file};
ReconSetupViewMore viewMore{nav_, view_rect, recon_lock_duration, recon_lock_nb_match, recon_match_mode};
ReconSetupViewMore viewMore{nav_, view_rect};
TabView tab_view{
{"Main", Color::cyan(), &viewMain},
+12 -22
View File
@@ -122,7 +122,7 @@ void ScannerThread::run() {
if (force_one_step)
_index_stepper = 0;
receiver_model.set_tuning_frequency(frequency_list_[frequency_index]); // Retune
receiver_model.set_target_frequency(frequency_list_[frequency_index]); // Retune
}
message.freq = frequency_list_[frequency_index];
message.range = frequency_index; // Inform freq (for coloring purposes also!)
@@ -160,7 +160,7 @@ void ScannerThread::run() {
if (force_one_step)
_index_stepper = 0;
receiver_model.set_tuning_frequency(frequency_range_.min + frequency_index * def_step_hz_); // Retune
receiver_model.set_target_frequency(frequency_range_.min + frequency_index * def_step_hz_); // Retune
}
message.freq = frequency_range_.min + frequency_index * def_step_hz_;
message.range = 0; // Inform freq (for coloring purposes also!)
@@ -299,14 +299,13 @@ ScannerView::ScannerView(
freqman_set_modulation_option(field_mode);
freqman_set_step_option(field_step);
// Default starting modulation (these may be overridden in SCANNER.TXT)
change_mode(AM_MODULATION); // Default modulation
field_mode.set_by_value(AM_MODULATION); // Reflect the mode into the manual selector
field_step.set_by_value(9000); // Default step interval (Hz)
// Default starting modulation (from saved App Settings if enabled, and may be overridden in SCANNER.TXT)
field_mode.set_by_value((OptionsField::value_t)receiver_model.modulation()); // Reflect the mode into the manual selector
field_step.set_by_value(receiver_model.frequency_step()); // Default step interval (Hz)
change_mode((freqman_index_t)field_mode.selected_index_value());
// FUTURE: perhaps additional settings should be stored in persistent memory vs using defaults
// HELPER: Pre-setting a manual range, based on stored frequency
rf::Frequency stored_freq = persistent_memory::tuned_frequency();
rf::Frequency stored_freq = receiver_model.target_frequency();
frequency_range.min = stored_freq - 1000000;
button_manual_start.set_text(to_string_short_freq(frequency_range.min));
frequency_range.max = stored_freq + 1000000;
@@ -458,7 +457,7 @@ ScannerView::ScannerView(
// Step field was changed (Hz) -- only affects manual Search mode
field_step.on_change = [this](size_t, OptionsField::value_t v) {
(void)v; // prevent compiler Unused warning
receiver_model.set_frequency_step(v);
if (manual_search && scan_thread) {
// Restart scan thread with new step value
@@ -759,31 +758,22 @@ void ScannerView::change_mode(freqman_index_t new_mod) { // Before this, do a s
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
field_bw.set_by_value(0);
receiver_model.set_am_configuration(field_bw.selected_index_value());
field_bw.set_by_value(receiver_model.am_configuration());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
break;
case NFM_MODULATION: // bw 16k (2) default
case NFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
field_bw.set_by_value(2);
receiver_model.set_nbfm_configuration(field_bw.selected_index_value());
field_bw.set_by_value(receiver_model.nbfm_configuration());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
break;
case WFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
field_bw.set_by_value(0);
receiver_model.set_wfm_configuration(field_bw.selected_index_value());
field_bw.set_by_value(receiver_model.wfm_configuration());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(2000000);
break;
default:
break;
+5
View File
@@ -22,6 +22,7 @@
#include "ui.hpp"
#include "receiver_model.hpp"
#include "radio_state.hpp"
#include "ui_receiver.hpp"
#include "ui_styles.hpp"
#include "freqman.hpp"
@@ -94,7 +95,11 @@ class ScannerView : public View {
// void set_parent_rect(const Rect new_parent_rect) override;
private:
app_settings::SettingsManager settings_{
"scanner", app_settings::Mode::RX};
NavigationView& nav_;
RxRadioState radio_state_{};
void start_scan_thread();
void change_mode(freqman_index_t mod_type);
+6 -8
View File
@@ -221,7 +221,7 @@ void SearchView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
slice_counter = 0;
} else
slice_counter++;
receiver_model.set_tuning_frequency(slices[slice_counter].center_frequency);
receiver_model.set_target_frequency(slices[slice_counter].center_frequency);
baseband::set_spectrum(SEARCH_SLICE_WIDTH, 31); // Clear
} else {
// Unique slice
@@ -271,7 +271,7 @@ void SearchView::on_range_changed() {
}
} else {
slices[0].center_frequency = (f_max + f_min) / 2;
receiver_model.set_tuning_frequency(slices[0].center_frequency);
receiver_model.set_target_frequency(slices[0].center_frequency);
slices_nb = 1;
text_slices.set(" 1");
@@ -376,25 +376,25 @@ SearchView::SearchView(
power_threshold = value;
};
field_frequency_min.set_value(receiver_model.tuning_frequency() - 1000000);
field_frequency_min.set_value(receiver_model.target_frequency() - 1000000);
field_frequency_min.set_step(100000);
field_frequency_min.on_change = [this](rf::Frequency) {
this->on_range_changed();
};
field_frequency_min.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->field_frequency_min.set_value(f);
};
};
field_frequency_max.set_value(receiver_model.tuning_frequency() + 1000000);
field_frequency_max.set_value(receiver_model.target_frequency() + 1000000);
field_frequency_max.set_step(100000);
field_frequency_max.on_change = [this](rf::Frequency) {
this->on_range_changed();
};
field_frequency_max.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->field_frequency_max.set_value(f);
};
@@ -415,8 +415,6 @@ SearchView::SearchView(
on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_sampling_rate(SEARCH_SLICE_WIDTH);
receiver_model.set_baseband_bandwidth(2500000);
receiver_model.enable();
}
+5
View File
@@ -21,6 +21,7 @@
*/
#include "receiver_model.hpp"
#include "radio_state.hpp"
#include "spectrum_color_lut.hpp"
@@ -89,6 +90,10 @@ class SearchView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
2500000 /* bandwidth */,
SEARCH_SLICE_WIDTH /* sampling rate */
};
struct slice_t {
rf::Frequency center_frequency;
+9 -13
View File
@@ -235,7 +235,6 @@ SetFrequencyCorrectionModel SetRadioView::form_collect() {
SetUIView::SetUIView(NavigationView& nav) {
add_children({&checkbox_disable_touchscreen,
&checkbox_speaker,
&checkbox_bloff,
&options_bloff,
&checkbox_showsplash,
@@ -246,7 +245,6 @@ SetUIView::SetUIView(NavigationView& nav) {
&button_cancel});
checkbox_disable_touchscreen.set_value(persistent_memory::disable_touchscreen());
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());
@@ -272,11 +270,6 @@ SetUIView::SetUIView(NavigationView& nav) {
persistent_memory::set_clock_with_date(false);
}
if (checkbox_speaker.value()) audio::output::speaker_mute(); // Just mute audio if speaker is disabled
persistent_memory::set_config_speaker(checkbox_speaker.value()); // Store Speaker status
StatusRefreshMessage message{}; // Refresh status bar with/out speaker
EventDispatcher::send_message(message);
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());
@@ -334,8 +327,8 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
if (!v) {
check_converter.set_value(false);
}
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
// Retune to take converter change in account.
receiver_model.set_target_frequency(receiver_model.target_frequency());
// Refresh status bar with/out converter
StatusRefreshMessage message{};
EventDispatcher::send_message(message);
@@ -349,7 +342,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
}
portapack::persistent_memory::set_config_converter(v);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
receiver_model.set_target_frequency(receiver_model.target_frequency());
// Refresh status bar with/out converter
StatusRefreshMessage message{};
EventDispatcher::send_message(message);
@@ -369,7 +362,7 @@ SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
new_view->on_changed = [this, &button](rf::Frequency f) {
portapack::persistent_memory::set_config_converter_freq(f);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
receiver_model.set_target_frequency(receiver_model.target_frequency());
button_converter_freq.set_text("<" + to_string_short_freq(f) + " MHz>");
};
};
@@ -412,7 +405,7 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
f = MAX_FREQ_CORRECTION;
portapack::persistent_memory::set_config_freq_rx_correction(f);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
receiver_model.set_target_frequency(receiver_model.target_frequency());
button_freq_rx_correction.set_text("<" + to_string_short_freq(f) + " MHz>");
};
};
@@ -425,7 +418,7 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
f = MAX_FREQ_CORRECTION;
portapack::persistent_memory::set_config_freq_tx_correction(f);
// Retune to take converter change in account
receiver_model.set_tuning_frequency(portapack::persistent_memory::tuned_frequency());
receiver_model.set_target_frequency(receiver_model.target_frequency());
button_freq_tx_correction.set_text("<" + to_string_short_freq(f) + " MHz>");
};
};
@@ -524,13 +517,16 @@ void SetPersistentMemoryView::focus() {
SetAudioView::SetAudioView(NavigationView& nav) {
add_children({&labels,
&field_tone_mix,
&checkbox_speaker_disable,
&button_save,
&button_cancel});
field_tone_mix.set_value(persistent_memory::tone_mix());
checkbox_speaker_disable.set_value(persistent_memory::config_speaker_disable());
button_save.on_select = [&nav, this](Button&) {
persistent_memory::set_tone_mix(field_tone_mix.value());
persistent_memory::set_config_speaker_disable(checkbox_speaker_disable.value());
nav.pop();
};
+13 -13
View File
@@ -212,17 +212,12 @@ class SetUIView : public View {
20,
"Disable touchscreen"};
Checkbox checkbox_speaker{
{3 * 8, 4 * 16},
20,
"Hide H1 Speaker option"};
Checkbox checkbox_bloff{
{3 * 8, 6 * 16},
{3 * 8, 4 * 16},
20,
"Backlight off after:"};
OptionsField options_bloff{
{52, 7 * 16 + 8},
{60, 5 * 16 + 8},
20,
{
{"5 seconds", backlight_timeout_t::Timeout5Sec},
@@ -236,25 +231,25 @@ class SetUIView : public View {
}};
Checkbox checkbox_showsplash{
{3 * 8, 9 * 16},
{3 * 8, 7 * 16},
20,
"Show splash"};
Checkbox checkbox_showclock{
{3 * 8, 11 * 16},
{3 * 8, 9 * 16},
20,
"Show clock with:"};
OptionsField options_clockformat{
{52, 12 * 16 + 8},
{60, 10 * 16 + 8},
20,
{{"time only", 0},
{"time and date", 1}}};
Checkbox checkbox_guireturnflag{
{3 * 8, 14 * 16},
{3 * 8, 12 * 16},
25,
"add return icon in GUI"};
"Show return icon in GUI"};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
@@ -393,6 +388,11 @@ class SetAudioView : public View {
1,
'0'};
Checkbox checkbox_speaker_disable{
{2 * 8, 6 * 16},
25,
"Disable AK speaker amp"};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
@@ -470,7 +470,7 @@ class SetPersistentMemoryView : public View {
private:
Text text_pmem_about{
{0, 1 * 16, 240, 16},
"PersistentMemory from/to SD"};
"Persistent Memory from/to SD"};
Text text_pmem_informations{
{0, 2 * 16, 240, 16},
+2 -4
View File
@@ -119,12 +119,10 @@ SIGFRXView::SIGFRXView(
.sampling_rate = 3072000,
.decimation_factor = 4,
});
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.set_tuning_frequency(868110000);
// TODO: use settings.
receiver_model.set_lna(0);
receiver_model.set_vga(0);
receiver_model.set_target_frequency(868110000);
add_children({&text_type,
&text_channel,
+3
View File
@@ -32,6 +32,7 @@
#include "max2837.hpp"
#include "volume.hpp"
#include "receiver_model.hpp"
#include "radio_state.hpp"
namespace ui {
@@ -50,6 +51,8 @@ class SIGFRXView : public View {
uint8_t last_channel;
uint8_t detect_counter = 0;
RxRadioState radio_state_{};
const uint16_t sigfrx_marks[18] = {
10, 8, 0,
60, 52, 90,
+2 -5
View File
@@ -54,9 +54,6 @@ void SigGenView::update_tone() {
}
void SigGenView::start_tx() {
transmitter_model.set_sampling_rate(1536000);
// transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
update_tone();
@@ -116,9 +113,9 @@ SigGenView::SigGenView(
};
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
};
};
+9
View File
@@ -23,6 +23,8 @@
#ifndef __SIGGEN_H__
#define __SIGGEN_H__
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
@@ -48,6 +50,13 @@ class SigGenView : public View {
void update_tone();
void on_tx_progress(const uint32_t progress, const bool done);
TxRadioState radio_state_{
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_siggen", app_settings::Mode::TX};
const std::string shape_strings[7] = {
"CW-just carrier",
"Sine signal ",
+5 -35
View File
@@ -65,27 +65,18 @@ SondeView::SondeView(NavigationView& nav) {
&button_see_qr,
&button_see_map});
// 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();
if (!settings_.loaded())
receiver_model.set_target_frequency(initial_target_frequency);
field_frequency.set_value(target_frequency_);
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning
field_frequency.on_change = [this](rf::Frequency f) {
set_target_frequency(f);
field_frequency.set_value(f);
receiver_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
set_target_frequency(f);
field_frequency.set_value(f);
};
};
@@ -104,9 +95,6 @@ SondeView::SondeView(NavigationView& nav) {
use_crc = v;
};
receiver_model.set_tuning_frequency(tuning_frequency());
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
receiver_model.enable();
// QR code with geo URI
@@ -129,7 +117,6 @@ SondeView::SondeView(NavigationView& nav) {
logger->append(LOG_ROOT_DIR "/SONDE.TXT");
audio::output::start();
audio::output::speaker_unmute();
// inject a PitchRSSIConfigureMessage in order to arm
// the pitch rssi events that will be used by the
@@ -142,10 +129,6 @@ 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);
receiver_model.disable();
@@ -216,15 +199,11 @@ void SondeView::on_packet(const sonde::Packet& packet) {
temp_humid_info = packet.get_temp_humid();
if (temp_humid_info.humid != 0) {
double decimals = abs(get_decimals(temp_humid_info.humid, 10, true));
// if (decimals < 0)
// decimals = -decimals;
text_humid.set(to_string_dec_int((int)temp_humid_info.humid) + "." + to_string_dec_uint(decimals, 1) + "%");
}
if (temp_humid_info.temp != 0) {
double decimals = abs(get_decimals(temp_humid_info.temp, 10, true));
// if (decimals < 0)
// decimals = -decimals;
text_temp.set(to_string_dec_int((int)temp_humid_info.temp) + "." + to_string_dec_uint(decimals, 1) + "C");
}
@@ -244,13 +223,4 @@ void SondeView::on_packet(const sonde::Packet& packet) {
}
}
void SondeView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(target_frequency_);
}
uint32_t SondeView::tuning_frequency() const {
return target_frequency_ - (sampling_rate / 4);
}
} /* namespace ui */
+9 -8
View File
@@ -35,6 +35,7 @@
#include "sonde_packet.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include <cstddef>
#include <string>
@@ -54,8 +55,7 @@ namespace ui {
class SondeView : public View {
public:
static constexpr uint32_t sampling_rate = 2457600;
static constexpr uint32_t baseband_bandwidth = 1750000;
static constexpr uint32_t initial_target_frequency = 402700000;
SondeView(NavigationView& nav);
~SondeView();
@@ -65,6 +65,13 @@ class SondeView : public View {
std::string title() const override { return "Radiosnd RX"; };
private:
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_sonde", app_settings::Mode::RX};
std::unique_ptr<SondeLogger> logger{};
uint32_t target_frequency_{402700000};
bool logging{false};
@@ -72,9 +79,6 @@ class SondeView : public View {
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{};
@@ -177,9 +181,6 @@ class SondeView : public View {
void on_packet(const sonde::Packet& packet);
char* float_to_char(float x, char* p);
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};
} /* namespace ui */
@@ -20,7 +20,6 @@
*/
#include "ui_spectrum_painter.hpp"
#include "cpld_update.hpp"
#include "bmp.hpp"
#include "baseband_api.hpp"
@@ -29,12 +28,14 @@
#include "file.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace ui {
SpectrumPainterView::SpectrumPainterView(
NavigationView& nav)
: nav_(nav) {
baseband::run_image(portapack::spi_flash::image_tag_spectrum_painter);
baseband::run_image(spi_flash::image_tag_spectrum_painter);
add_children({
&labels,
@@ -56,30 +57,29 @@ SpectrumPainterView::SpectrumPainterView(
input_image.set_parent_rect(view_rect);
input_text.set_parent_rect(view_rect);
field_frequency.set_value(target_frequency());
field_frequency.set_value(transmitter_model.target_frequency());
field_frequency.set_step(5000);
field_frequency.on_change = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
transmitter_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(this->target_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
this->on_target_frequency_changed(f);
this->field_frequency.set_value(f);
field_frequency.set_value(f);
};
};
tx_gain = portapack::transmitter_model.tx_gain();
tx_gain = transmitter_model.tx_gain();
field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ).
field_rfgain.on_change = [this](int32_t v) { // allow initial value change just after opened file.
tx_gain = v;
portapack::transmitter_model.set_tx_gain(tx_gain);
transmitter_model.set_tx_gain(tx_gain);
};
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;
portapack::transmitter_model.set_rf_amp(rf_amp);
transmitter_model.set_rf_amp(rf_amp);
};
input_image.on_input_avaliable = [this]() {
@@ -93,11 +93,9 @@ SpectrumPainterView::SpectrumPainterView(
if (tx_mode == 0 && image_input_avaliable == false)
return;
portapack::transmitter_model.set_sampling_rate(3072000U);
portapack::transmitter_model.set_baseband_bandwidth(1750000);
portapack::transmitter_model.enable();
transmitter_model.enable();
if (portapack::persistent_memory::stealth_mode()) {
if (persistent_memory::stealth_mode()) {
DisplaySleepMessage message;
EventDispatcher::send_message(message);
}
@@ -137,7 +135,7 @@ void SpectrumPainterView::start_tx() {
void SpectrumPainterView::stop_tx() {
button_play.set_bitmap(&bitmap_play);
portapack::transmitter_model.disable();
transmitter_model.disable();
tx_active = false;
tx_current_line = 0;
}
@@ -176,8 +174,7 @@ void SpectrumPainterView::frame_sync() {
}
SpectrumPainterView::~SpectrumPainterView() {
portapack::transmitter_model.disable();
hackrf::cpld::load_sram_no_verify();
transmitter_model.disable();
baseband::shutdown();
}
@@ -185,18 +182,6 @@ void SpectrumPainterView::focus() {
tab_view.focus();
}
void SpectrumPainterView::on_target_frequency_changed(rf::Frequency f) {
set_target_frequency(f);
}
void SpectrumPainterView::set_target_frequency(const rf::Frequency new_value) {
portapack::persistent_memory::set_tuned_frequency(new_value);
}
rf::Frequency SpectrumPainterView::target_frequency() const {
return portapack::persistent_memory::tuned_frequency();
}
void SpectrumPainterView::paint(Painter& painter) {
View::paint(painter);
@@ -29,6 +29,8 @@
#include "capture_app.hpp"
#include "baseband_api.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "portapack.hpp"
#include "message.hpp"
@@ -53,11 +55,11 @@ class SpectrumPainterView : public View {
std::string title() const override { return "Spec.Painter"; };
private:
void on_target_frequency_changed(rf::Frequency f);
void set_target_frequency(const rf::Frequency new_value);
rf::Frequency target_frequency() const;
NavigationView& nav_;
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_painter", app_settings::Mode::TX};
bool image_input_avaliable{false};
bool tx_active{false};
uint32_t tx_mode{0};
+4 -24
View File
@@ -25,7 +25,6 @@
#include "portapack.hpp"
#include "hackrf_hal.hpp"
#include "cpld_update.hpp"
#include <cstring>
#include <stdio.h>
@@ -88,17 +87,8 @@ 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();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
}
void SSTVTXView::on_tuning_frequency_changed(rf::Frequency f) {
transmitter_model.set_tuning_frequency(f);
baseband::shutdown();
}
void SSTVTXView::prepare_scanline() {
@@ -170,8 +160,6 @@ void SSTVTXView::start_tx() {
scanline_counter = 0;
prepare_scanline(); // Preload one scanline
transmitter_model.set_sampling_rate(3072000U);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_sstv_data(
@@ -218,15 +206,6 @@ 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()) {
@@ -284,9 +263,10 @@ SSTVTXView::SSTVTXView(
on_mode_changed(1);
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
transmitter_model.set_target_frequency(f);
// NB: The freq field is only updated because TXView's on_show runs again.
};
};
+4 -4
View File
@@ -34,6 +34,7 @@
#include "file.hpp"
#include "bmp.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
using namespace sstv;
@@ -56,11 +57,11 @@ class SSTVTXView : public View {
private:
NavigationView& nav_;
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_sstv", app_settings::Mode::TX};
sstv_scanline scanline_buffer{};
// app save settings
std::app_settings settings{};
std::app_settings::AppSettings app_settings{};
bool file_error{false};
File bmp_file{};
@@ -75,7 +76,6 @@ class SSTVTXView : public View {
void read_boundary(uint8_t* buffer, uint32_t position, uint32_t length);
void on_bitmap_changed(const size_t index);
void on_mode_changed(const size_t index);
void on_tuning_frequency_changed(rf::Frequency f);
void start_tx();
void prepare_scanline();
+3 -17
View File
@@ -54,17 +54,15 @@ TestView::TestView(NavigationView& nav) {
&button_cal,
&check_log});
field_frequency.set_value(target_frequency_);
field_frequency.set_value(receiver_model.target_frequency());
field_frequency.set_step(10000);
field_frequency.on_change = [this](rf::Frequency f) {
set_target_frequency(f);
field_frequency.set_value(f);
receiver_model.set_target_frequency(f);
};
field_frequency.on_edit = [this, &nav]() {
// TODO: Provide separate modal method/scheme?
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
set_target_frequency(f);
field_frequency.set_value(f);
};
};
@@ -81,9 +79,6 @@ TestView::TestView(NavigationView& nav) {
if (logger)
logger->append("saucepan.txt");
receiver_model.set_tuning_frequency(tuning_frequency());
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
receiver_model.enable();
}
@@ -130,13 +125,4 @@ void TestView::on_packet(const testapp::Packet& packet) {
longitude = packet.GPS_longitude();*/
}
void TestView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
receiver_model.set_tuning_frequency(tuning_frequency());
}
uint32_t TestView::tuning_frequency() const {
return target_frequency_ - (sampling_rate / 4);
}
} /* namespace ui */
+6 -7
View File
@@ -51,9 +51,6 @@ namespace ui {
class TestView : public View {
public:
static constexpr uint32_t sampling_rate = 2457600 * 2;
static constexpr uint32_t baseband_bandwidth = 1750000;
TestView(NavigationView& nav);
~TestView();
@@ -62,7 +59,11 @@ class TestView : public View {
std::string title() const override { return "Test app"; };
private:
uint32_t target_frequency_{439206000};
RxRadioState radio_state_{
1750000 /* bandwidth */,
2457600 * 2 /* sampling rate */
};
Coord cur_x{0};
uint32_t packet_count{0};
uint32_t packets_lost{0};
@@ -112,12 +113,10 @@ class TestView : public View {
[this](Message* const p) {
const auto message = static_cast<const TestAppPacketMessage*>(p);
const testapp::Packet packet{message->packet};
this->on_packet(packet);
on_packet(packet);
}};
void on_packet(const testapp::Packet& packet);
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};
} /* namespace ui */
+3 -1
View File
@@ -115,8 +115,10 @@ bool TextViewer::on_encoder(EncoderEvent delta) {
if (cursor_.dir == ScrollDirection::Horizontal)
updated = apply_scrolling_constraints(0, delta);
else
else {
delta *= 16;
updated = apply_scrolling_constraints(delta, 0);
}
if (updated)
redraw();
+3 -7
View File
@@ -26,7 +26,6 @@
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "cpld_update.hpp"
using namespace portapack;
using namespace encoders;
@@ -39,8 +38,7 @@ void TouchTunesView::focus() {
TouchTunesView::~TouchTunesView() {
transmitter_model.disable();
hackrf::cpld::load_sram_no_verify(); // to leave all RX ok, without ghost signal problem at the exit.
baseband::shutdown(); // better this function at the end, not load_sram() that sometimes produces hang up.
baseband::shutdown();
}
void TouchTunesView::stop_tx() {
@@ -87,10 +85,8 @@ void TouchTunesView::on_tx_progress(const uint32_t progress, const bool done) {
// transmission events.
void TouchTunesView::start_ew() {
// Radio
transmitter_model.set_tuning_frequency(433920000);
transmitter_model.set_sampling_rate(3072000U);
transmitter_model.set_target_frequency(433920000);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(3500000U);
transmitter_model.set_tx_gain(47);
transmitter_model.enable();
@@ -155,7 +151,7 @@ void TouchTunesView::start_tx(const uint32_t button_index) {
size_t bitstream_length = make_bitstream(fragments);
transmitter_model.set_tuning_frequency(433920000);
transmitter_model.set_target_frequency(433920000);
transmitter_model.set_sampling_rate(OOK_SAMPLERATE);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000);
@@ -24,6 +24,7 @@
#include "ui.hpp"
#include "ui_transmitter.hpp"
#include "transmitter_model.hpp"
#include "radio_state.hpp"
// The coding in notpike's script is quite complex, using multiple LUTs to form the data sent to the YSO.
// The format is actually very simple if it is rather seen as short and long gaps between pulses (as seen in many OOK remotes).
@@ -113,6 +114,11 @@ class TouchTunesView : public View {
std::string title() const override { return "TouchTunes"; };
private:
TxRadioState radio_state_{
3500000 /* bandwidth */,
3072000 /* sampling rate */
};
uint32_t scan_button_index{};
uint32_t pin{0};

Some files were not shown because too many files have changed in this diff Show More