Compare commits

...

22 Commits

Author SHA1 Message Date
Mark Thompson d5c8525afc Declare all folder names in a single source file (#2039) 2024-03-25 08:44:49 +01:00
ImDroided d9bbd1b9ff SSTV Freqs (#2038)
* Added and fixed freqs

Figured I would clean these up and add a bit.

* Create SSTV.TXT

SSTV Frequencies for SSTV app
2024-03-25 01:21:05 -05:00
gullradriel b47cee435e fix typo (#2037) 2024-03-24 18:50:42 -05:00
gullradriel c078bac0e7 Looking glass beep (#2036)
* first draft of looking beep
* fixed beep squelch range in percent
* took out steps 
* gui adjustements
* uniformize calculation and beep squelch in db
* uniformisation, fix 24/48 error
2024-03-24 22:32:13 +01:00
gullradriel 6177b08632 fixing level beep, bad copy paste on special SPEC mode (#2035)
Co-authored-by: gullradriel <gullradriel@no-mail.com>
2024-03-24 18:47:15 +08:00
Mark Thompson 53a1bacd46 Revert "Add cmake dependency on baseband for external APPS" (#2034)
This reverts commit abb9b6c8ad.
2024-03-24 10:39:20 +08:00
ImDroided 4c012a9493 Added and fixed freqs (#2033)
Figured I would clean these up and add a bit.
2024-03-23 21:16:27 -05:00
Mark Thompson abb9b6c8ad Add make dependency on baseband for external APPS (#2031) 2024-03-23 21:34:15 +01:00
gullradriel 6e2507d609 fix gui glitch on beep squelch (#2030) 2024-03-23 21:01:48 +01:00
gullradriel 536981998b Level fix and beep, RSSI avg fix (#2027)
* fix average value being overflow'd
* fix audio and mod changes, preps for beep mode
* fixed beep_freq range, added a stop and set a variable sooner
* added support for audio beep messages
* better scaler for beep
* added bip squelch and saving of bip squelch and audio mode
* saving modulation, fixing audio
* added save and restore of bandwidth
* simpler ctcss clean on change mode
2024-03-23 19:27:05 +01:00
Mark Thompson 1a87f2d701 Revert accidental newbutton bg color change (#2029) 2024-03-23 13:26:46 -05:00
Mark Thompson 81e24d582d More debug Audio Beep Test tweaks (#2028) 2024-03-23 13:25:36 -05:00
Mark Thompson 28a5fc5915 Improved Audio Beep Test (#2026) 2024-03-23 08:21:35 +01:00
Mark Thompson ba4290cf0d Audio Beep Test (Debug) external app (#2023) 2024-03-22 11:10:16 +01:00
Mark Thompson 692644d214 Radiosonde QR code fixes (#2021)
* Increase size of small QR Code

* Fixed QR code lat/lon for iPhone

* Show current geopos location on map

* Deprecate large QR code
2024-03-21 10:56:06 -05:00
Mark Thompson 4aeaf94d2d Radiosonde beep tone tweaks (#2020)
* Tweak RSSI audio beep frequency range
* Clang & changed min freq
* Save beep/log/crc settings in .ini file
* Update copyright string
* Added generic audio_beep message
2024-03-21 10:14:54 +01:00
Totoo 8391ca8052 Fox hunt (#2015)
* foxhunt_rx
2024-03-19 21:33:53 +01:00
Mark Thompson 807c76346b Improved audio beep tone (#2014)
* Improved sine wave beep tone

* Prevent divide-by-zero
2024-03-19 15:30:05 -05:00
Mark Thompson 308573918c Added a beep duration parameter (#2013) 2024-03-19 18:23:06 +01:00
Mark Thompson 74442f197d Fixed Sonde RSSI "Beep" (#2012) 2024-03-19 10:53:55 +01:00
Mark Thompson b53c8e1f80 Stop audio DMA in baseband::shutdown() (#2011) 2024-03-19 05:58:23 +01:00
Mark Thompson c5f73cf8f4 Darken FileMan button colors for visibility (#2010) 2024-03-19 05:56:23 +01:00
94 changed files with 1456 additions and 443 deletions
+1
View File
@@ -190,6 +190,7 @@ set(CPPSRC
event_m0.cpp
file_reader.cpp
file.cpp
file_path.cpp
freqman_db.cpp
freqman.cpp
io_convert.cpp
+3 -2
View File
@@ -30,6 +30,7 @@
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include <algorithm>
#include <cstring>
@@ -40,7 +41,7 @@ using namespace portapack;
namespace {
fs::path get_settings_path(const std::string& app_name) {
return fs::path{SETTINGS_DIR} / app_name + u".ini";
return settings_dir / app_name + u".ini";
}
} // namespace
@@ -156,7 +157,7 @@ bool save_settings(std::string_view store_name, const SettingBindings& bindings)
File f;
auto path = get_settings_path(std::string{store_name});
ensure_directory(SETTINGS_DIR);
ensure_directory(settings_dir);
auto error = f.create(path);
if (error)
return false;
-3
View File
@@ -36,9 +36,6 @@
#include "max283x.hpp"
#include "string_format.hpp"
// Folder to store app settings, pmem_fileflag, and date_fileflag
#define SETTINGS_DIR u"/SETTINGS"
// Bring in the string_view literal.
using std::literals::operator""sv;
+2 -1
View File
@@ -24,6 +24,7 @@
#include "baseband_api.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace acars;
@@ -77,7 +78,7 @@ ACARSAppView::ACARSAppView(NavigationView& nav)
logger = std::make_unique<ACARSLogger>();
if (logger)
logger->append(LOG_ROOT_DIR "/ACARS.TXT");
logger->append(logs_dir / u"ACARS.TXT");
}
ACARSAppView::~ACARSAppView() {
+1 -1
View File
@@ -35,7 +35,7 @@
class ACARSLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+2 -1
View File
@@ -23,6 +23,7 @@
#include "string_format.hpp"
#include "database.hpp"
#include "file_path.hpp"
#include "baseband_api.hpp"
@@ -399,7 +400,7 @@ AISAppView::AISAppView(NavigationView& nav)
logger = std::make_unique<AISLogger>();
if (logger) {
logger->append(LOG_ROOT_DIR "/AIS.TXT");
logger->append(logs_dir / u"AIS.TXT");
}
}
+2 -1
View File
@@ -32,6 +32,7 @@
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "ui_text.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace modems;
@@ -100,7 +101,7 @@ BLECommView::BLECommView(NavigationView& nav)
logging = v;
if (logger && logging)
logger->append(LOG_ROOT_DIR "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
logger->append(logs_dir.string() + "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
};
options_channel.on_change = [this](size_t, int32_t i) {
+1 -1
View File
@@ -42,7 +42,7 @@
class BLECommLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+1 -4
View File
@@ -470,10 +470,7 @@ BLERxView::BLERxView(NavigationView& nav)
logging = v;
if (logger && logging)
logger->append(
"BLERX/Logs"
"/BLELOG_" +
to_string_timestamp(rtc_time::now()) + ".TXT");
logger->append(blerx_dir.string() + "/Logs/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
};
check_log.set_value(logging);
+6 -5
View File
@@ -36,12 +36,13 @@
#include "log_file.hpp"
#include "utility.hpp"
#include "usb_serial_thread.hpp"
#include "file_path.hpp"
#include "recent_entries.hpp"
class BLELogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
@@ -133,7 +134,7 @@ class BleRecentEntryDetailView : public View {
void on_save_file(const std::string value, BLETxPacket packetToSave);
bool saveFile(const std::filesystem::path& path, BLETxPacket packetToSave);
std::string packetFileBuffer{};
std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"};
std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"};
static constexpr uint8_t total_data_lines{5};
@@ -250,9 +251,9 @@ class BLERxView : public View {
uint64_t total_count = 0;
std::vector<std::string> searchList{};
std::filesystem::path find_packet_path{u"BLERX/Find/????.TXT"};
std::filesystem::path log_packets_path{u"BLERX/Logs/????.TXT"};
std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"};
std::filesystem::path find_packet_path{blerx_dir / u"Find/????.TXT"};
std::filesystem::path log_packets_path{blerx_dir / u"Logs/????.TXT"};
std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"};
static constexpr auto header_height = 4 * 16;
static constexpr auto switch_button_height = 3 * 16;
+1
View File
@@ -34,6 +34,7 @@
#include "portapack_persistent_memory.hpp"
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace modems;
+4 -3
View File
@@ -36,6 +36,7 @@
#include "replay_thread.hpp"
#include "log_file.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include "recent_entries.hpp"
@@ -44,7 +45,7 @@
class BLELoggerTx {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
@@ -138,7 +139,7 @@ class BLETxView : public View {
uint32_t prev_value{0};
std::filesystem::path file_path{};
std::filesystem::path packet_save_path{u"BLETX/BLETX_????.TXT"};
std::filesystem::path packet_save_path{bletx_dir / u"BLETX_????.TXT"};
uint8_t channel_number = 37;
bool auto_channel = false;
@@ -165,7 +166,7 @@ class BLETxView : public View {
std::unique_ptr<FileWrapper> dataFileWrapper{};
File dataFile{};
std::filesystem::path dataTempFilePath{u"BLETX/dataFileTemp.TXT"};
std::filesystem::path dataTempFilePath{bletx_dir / u"dataFileTemp.TXT"};
std::vector<uint16_t> markedBytes{};
CursorPos cursor_pos{};
uint8_t marked_counter = 0;
+2 -1
View File
@@ -31,6 +31,7 @@
#include "ui_spectrum.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "file_path.hpp"
namespace ui {
@@ -101,7 +102,7 @@ class CaptureAppView : public View {
RecordView record_view{
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
u"BBD_????.*",
u"CAPTURES",
captures_dir,
RecordView::FileType::RawS16,
16384,
3};
+2 -1
View File
@@ -31,6 +31,7 @@ using namespace portapack;
#include "crc.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
namespace ert {
@@ -129,7 +130,7 @@ ERTAppView::ERTAppView(NavigationView& nav)
logger = std::make_unique<ERTLogger>();
if (logger) {
logger->append(LOG_ROOT_DIR "/ERT.TXT");
logger->append(logs_dir / u"ERT.TXT");
}
}
+2 -1
View File
@@ -27,6 +27,7 @@
#include "portapack_persistent_memory.hpp"
#include "string_format.hpp"
#include "utility.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace pocsag;
@@ -115,7 +116,7 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav)
: FILTER_DROP;
}
logger.append(LOG_ROOT_DIR "/POCSAG.TXT");
logger.append(logs_dir / u"POCSAG.TXT");
field_squelch.set_value(receiver_model.squelch_level());
field_squelch.on_change = [this](int32_t v) {
+1 -1
View File
@@ -39,7 +39,7 @@
class POCSAGLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+3 -2
View File
@@ -28,6 +28,7 @@
#include "tonesets.hpp"
#include "ui_tone_key.hpp"
#include "audio.hpp"
#include "file_path.hpp"
using namespace tonekey;
using namespace portapack;
@@ -164,7 +165,7 @@ void SoundBoardView::refresh_list() {
// List directories and files, put directories up top
uint32_t count = 0;
for (const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*")) {
for (const auto& entry : std::filesystem::directory_iterator(wav_dir, u"*")) {
if (std::filesystem::is_regular_file(entry.status())) {
if (entry.path().string().length()) {
auto entry_extension = entry.path().extension().string();
@@ -173,7 +174,7 @@ void SoundBoardView::refresh_list() {
c = toupper(c);
if (entry_extension == ".WAV") {
if (reader->open(u"/WAV/" + entry.path().native())) {
if (reader->open(wav_dir / entry.path())) {
if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) {
// sounds[c].ms_duration = reader->ms_duration();
// sounds[c].path = u"WAV/" + entry.path().native();
+2 -1
View File
@@ -30,6 +30,7 @@ using namespace portapack;
#include "string_format.hpp"
#include "utility.hpp"
#include "file_path.hpp"
namespace tpms {
@@ -176,7 +177,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
logger = std::make_unique<TPMSLogger>();
if (logger) {
logger->append(LOG_ROOT_DIR "/TPMS.TXT");
logger->append(logs_dir / u"TPMS.TXT");
}
}
+2 -1
View File
@@ -31,6 +31,7 @@
#include "portapack_persistent_memory.hpp"
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "file_path.hpp"
using namespace portapack;
@@ -390,7 +391,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
};
logger = std::make_unique<ADSBLogger>();
logger->append(LOG_ROOT_DIR "/ADSB.TXT");
logger->append(logs_dir / u"ADSB.TXT");
receiver_model.enable();
baseband::set_adsb();
+2 -1
View File
@@ -27,6 +27,7 @@
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
using namespace portapack;
@@ -111,7 +112,7 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
logger = std::make_unique<APRSLogger>();
if (logger)
logger->append(LOG_ROOT_DIR "/APRS.TXT");
logger->append(logs_dir / u"APRS.TXT");
baseband::set_aprs(1200);
+3 -2
View File
@@ -36,10 +36,11 @@
#include "log_file.hpp"
#include "utility.hpp"
#include "file_path.hpp"
class APRSLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
@@ -232,7 +233,7 @@ class APRSRxView : public View {
RecordView record_view{
{0 * 8, 1 * 16, 30 * 8, 1 * 16},
u"AFS_????.WAV",
u"APRS",
aprs_dir,
RecordView::FileType::WAV,
4096,
4};
+1 -1
View File
@@ -280,7 +280,7 @@ class FileManagerView : public FileManBaseView {
{4 * 8, 29 * 8, 4 * 8, 32},
{},
&bitmap_icon_options_datetime,
Color::orange(),
Color::dark_blue(),
/*vcenter*/ true};
NewButton button_open_iq_trim{
@@ -23,11 +23,10 @@
#include "ui_flash_utility.hpp"
#include "ui_styles.hpp"
#include "portapack_shared_memory.hpp"
#include "file_path.hpp"
namespace ui {
static const std::filesystem::path firmware_path = u"/FIRMWARE";
// Firmware image validation
static const char* hackrf_magic = "HACKRFFW";
#define FIRMWARE_INFO_AREA_OFFSET 0x400
@@ -84,7 +83,7 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav)
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
ensure_directory(firmware_path);
ensure_directory(firmware_dir);
auto add_firmware_items = [&](
const std::filesystem::path& folder_path,
@@ -103,8 +102,8 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav)
}
};
add_firmware_items(firmware_path, u"*.bin", ui::Color::red());
add_firmware_items(firmware_path, u"*.tar", ui::Color::purple());
add_firmware_items(firmware_dir, u"*.bin", ui::Color::red());
add_firmware_items(firmware_dir, u"*.tar", ui::Color::purple());
// add_firmware_items(user_firmware_folder,u"*.bin", ui::Color::purple());
}
@@ -116,7 +115,7 @@ void FlashUtilityView::firmware_selected(std::filesystem::path::string_type path
YESNO,
[this, path](bool choice) {
if (choice) {
std::u16string full_path = std::u16string(u"FIRMWARE/") + path;
std::filesystem::path::string_type full_path = firmware_dir.native() + u"/" + path;
this->flash_firmware(full_path);
}
});
+1
View File
@@ -31,6 +31,7 @@
#include "ui_receiver.hpp"
#include "ui_styles.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include <memory>
+2 -1
View File
@@ -27,6 +27,7 @@
#include "portapack_persistent_memory.hpp"
#include "string_format.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include "ui_freqman.hpp"
@@ -134,7 +135,7 @@ FskxRxMainView::FskxRxMainView(NavigationView& nav)
field_frequency.set_value(initial_target_frequency);
deviation_frequency.set_value(initial_deviation);
logger.append(LOG_ROOT_DIR "/FSKRX.TXT");
logger.append(logs_dir / u"FSKRX.TXT");
baseband::set_fsk(initial_deviation);
+1 -1
View File
@@ -42,7 +42,7 @@
class FskRxLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+2 -1
View File
@@ -25,6 +25,7 @@
#include "complex.hpp"
#include "portapack.hpp"
#include "ui_fileman.hpp"
#include "file_path.hpp"
using namespace portapack;
namespace fs = std::filesystem;
@@ -47,7 +48,7 @@ IQTrimView::IQTrimView(NavigationView& nav)
field_path.on_select = [this](TextField&) {
auto open_view = nav_.push<FileLoadView>(".C*");
open_view->push_dir(u"CAPTURES");
open_view->push_dir(captures_dir);
open_view->on_changed = [this](fs::path path) {
open_file(path);
};
+88 -26
View File
@@ -35,6 +35,30 @@ using portapack::memory::map::backup_ram;
namespace ui {
// Function to map the value from one range to another
int32_t LevelView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) {
return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow);
}
void LevelView::m4_manage_stat_update() {
if (audio_mode) {
if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) {
shared_memory.request_m4_performance_counter = 1;
} else {
shared_memory.request_m4_performance_counter = 2;
}
if (radio_mode == SPEC_MODULATION) {
beep = true;
}
} else {
shared_memory.request_m4_performance_counter = 2;
if (radio_mode == SPEC_MODULATION) {
beep = false;
baseband::request_beep_stop();
}
}
}
void LevelView::focus() {
button_frequency.focus();
}
@@ -62,18 +86,15 @@ LevelView::LevelView(NavigationView& nav)
&freq_stats_rssi,
&freq_stats_db,
&freq_stats_rx,
&audio_mode,
&text_beep_squelch,
&field_beep_squelch,
&field_audio_mode,
&peak_mode,
&rssi,
&rssi_graph});
// activate vertical bar mode
rssi.set_vertical_rssi(true);
// activate counters for RxSat
shared_memory.request_m4_performance_counter = 2;
change_mode(NFM_MODULATION); // Start on AM
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector
freq_ = receiver_model.target_frequency();
button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>");
@@ -87,6 +108,11 @@ LevelView::LevelView(NavigationView& nav)
};
};
field_beep_squelch.set_value(beep_squelch);
field_beep_squelch.on_change = [this](int32_t v) {
beep_squelch = v;
};
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);
@@ -102,17 +128,14 @@ LevelView::LevelView(NavigationView& nav)
button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>");
};
freqman_set_modulation_option(field_mode);
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) {
receiver_model.disable();
baseband::shutdown();
change_mode(v);
if (audio_mode.selected_index() != 0) {
audio::output::start();
}
receiver_model.enable();
}
};
field_mode.set_by_value(radio_mode); // Reflect the mode into the manual selector
field_bw.set_selected_index(radio_bw);
rssi_resolution.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) {
@@ -120,15 +143,18 @@ LevelView::LevelView(NavigationView& nav)
}
};
audio_mode.on_change = [this](size_t, OptionsField::value_t v) {
field_audio_mode.on_change = [this](size_t, OptionsField::value_t v) {
audio_mode = v;
if (v == 0) {
audio::output::stop();
} else if (v == 1) {
audio::set_rate(audio_sampling_rate);
audio::output::start();
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
} else {
}
m4_manage_stat_update(); // rx_sat hack
};
field_audio_mode.set_selected_index(audio_mode);
peak_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v == 0) {
@@ -142,7 +168,6 @@ LevelView::LevelView(NavigationView& nav)
peak_mode.set_selected_index(2);
rssi_resolution.set_selected_index(1);
// FILL STEP OPTIONS
freqman_set_modulation_option(field_mode);
freqman_set_step_option_short(step_mode);
freq_stats_rssi.set_style(&Styles::white);
freq_stats_db.set_style(&Styles::white);
@@ -168,13 +193,28 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
last_min_rssi = rssi_graph.get_graph_min();
last_avg_rssi = rssi_graph.get_graph_avg();
last_max_rssi = rssi_graph.get_graph_max();
freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi) + ", dt: " + to_string_dec_uint(rssi_graph.get_graph_delta()));
freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi));
}
if (beep && statistics.max_db > beep_squelch) {
baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150);
}
// refresh sat
if (radio_mode == SPEC_MODULATION || (radio_mode == WFM_MODULATION && audio_mode == 1)) {
Style style_freq_stats_rx{
.font = font::fixed_8x16,
.background = {55, 55, 55},
.foreground = {155, 155, 155},
};
freq_stats_rx.set_style(&style_freq_stats_rx);
freq_stats_rx.set("RxSat off");
return;
}
uint8_t rx_sat = ((uint32_t)shared_memory.m4_performance_counter) * 100 / 127;
if (last_rx_sat != rx_sat) {
last_rx_sat = rx_sat;
freq_stats_rx.set("RxSat: " + to_string_dec_uint(rx_sat) + "%");
uint8_t br = 0;
uint8_t bg = 0;
uint8_t bb = 0;
@@ -191,6 +231,7 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
.foreground = {255, 255, 255},
};
freq_stats_rx.set_style(&style_freq_stats_rx);
freq_stats_rx.set("RxSat: " + to_string_dec_uint(rx_sat) + "%");
}
} /* on_statistic_updates */
@@ -198,44 +239,53 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
size_t LevelView::change_mode(freqman_index_t new_mod) {
field_bw.on_change = [this](size_t n, OptionsField::value_t) { (void)n; };
radio_mode = new_mod;
audio::output::stop();
receiver_model.disable();
baseband::shutdown();
switch (new_mod) {
case AM_MODULATION:
audio_sampling_rate = audio::Rate::Hz_12000;
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::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); };
// bw DSB (0) default
field_bw.set_by_value(0);
text_ctcss.set(" ");
receiver_model.set_am_configuration(0);
field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_am_configuration(n); };
break;
case NFM_MODULATION:
audio_sampling_rate = audio::Rate::Hz_24000;
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);
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); };
// bw 16k (2) default
field_bw.set_by_value(2);
field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_nbfm_configuration(n); };
break;
case WFM_MODULATION:
audio_sampling_rate = audio::Rate::Hz_48000;
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);
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); };
// bw 200k (0) only/default
// bw 200k (0) default
field_bw.set_by_value(0);
text_ctcss.set(" ");
field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); };
break;
case SPEC_MODULATION:
audio_sampling_rate = audio::Rate::Hz_24000;
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_capture);
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
// 12k5 (0) default
field_bw.on_change = [this](size_t index, OptionsField::value_t sampling_rate) {
radio_bw = index;
// Baseband needs to know the desired sampling and oversampling rates.
baseband::set_sample_rate(sampling_rate, get_oversample_rate(sampling_rate));
// The radio needs to know the effective sampling rate.
auto actual_sampling_rate = get_actual_sample_rate(sampling_rate);
receiver_model.set_sampling_rate(actual_sampling_rate);
@@ -250,6 +300,18 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
}
if (new_mod != NFM_MODULATION) {
text_ctcss.set(" ");
}
m4_manage_stat_update(); // rx_sat hack
if (audio_mode) {
audio::set_rate(audio_sampling_rate);
audio::output::start();
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
}
receiver_model.enable();
return step_mode.selected_index();
}
+40 -16
View File
@@ -55,14 +55,30 @@ class LevelView : public View {
NavigationView& nav_;
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_level", app_settings::Mode::RX};
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
size_t change_mode(freqman_index_t mod_type);
void on_statistics_update(const ChannelStatistics& statistics);
void set_display_freq(int64_t freq);
void m4_manage_stat_update(); // to finely adjust the RxSaturation usage
rf::Frequency freq_ = {0};
bool beep = false;
uint8_t radio_mode = 0;
uint8_t radio_bw = 0;
uint8_t audio_mode = 0;
int32_t beep_squelch = 0;
audio::Rate audio_sampling_rate = audio::Rate::Hz_48000;
app_settings::SettingsManager settings_{
"rx_level",
app_settings::Mode::RX,
{
{"beep_squelch"sv, &beep_squelch},
{"audio_mode"sv, &audio_mode},
{"radio_mode"sv, &radio_mode},
{"radio_bw"sv, &radio_bw},
}};
Labels labels{
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()},
@@ -100,23 +116,27 @@ class LevelView : public View {
{0 * 8, 2 * 16 + 8, 15 * 8, 1 * 8},
""};
OptionsField audio_mode{
OptionsField field_audio_mode{
{21 * 8, 1 * 16},
9,
{
{"audio off", 0},
{"audio on", 1}
//{"tone on", 2},
//{"tone off", 3},
}};
{{"audio off", 0},
{"audio on", 1}}};
Text text_ctcss{
{22 * 8, 3 * 16 + 4, 8 * 8, 1 * 8},
""};
Text text_beep_squelch{
{21 * 8, 3 * 16 + 4, 4 * 8, 1 * 8},
"Bip>"};
// RSSI: XX/XX/XXX,dt: XX
NumberField field_beep_squelch{
{25 * 8, 3 * 16 + 4},
4,
{-100, 20},
1,
' ',
};
// RSSI: XX/XX/XXX
Text freq_stats_rssi{
{0 * 8, 3 * 16 + 4, 22 * 8, 1 * 16},
{0 * 8, 3 * 16 + 4, 15 * 8, 1 * 16},
};
// Power: -XXX db
@@ -153,14 +173,18 @@ class LevelView : public View {
{0 * 8, 5 * 16 + 4, 10 * 8, 1 * 16},
};
Text text_ctcss{
{12 * 8, 5 * 16 + 4, 8 * 8, 1 * 8},
""};
RSSIGraph rssi_graph{
// 240x320 =>
{0, 6 * 16 + 4, 240 - 5 * 8, 320 - (6 * 16 + 4)},
{0, 6 * 16 + 8, 240 - 5 * 8, 320 - (6 * 16)},
};
RSSI rssi{
// 240x320 =>
{240 - 5 * 8, 6 * 16 + 4, 5 * 8, 320 - (6 * 16 + 4)},
{240 - 5 * 8, 6 * 16 + 8, 5 * 8, 320 - (6 * 16)},
};
void handle_coded_squelch(const uint32_t value);
@@ -25,6 +25,8 @@
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
#include "audio.hpp"
#include "file_path.hpp"
using namespace portapack;
@@ -34,11 +36,39 @@ void GlassView::focus() {
}
GlassView::~GlassView() {
audio::output::stop();
receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps
receiver_model.disable();
baseband::shutdown();
}
// Function to map the value from one range to another
int32_t GlassView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) {
return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow);
}
void GlassView::update_display_beep() {
if (beep_enabled) {
button_beep_squelch.set_style(&Styles::green);
// <bip:-XXXdb>
button_beep_squelch.set_text("[bip>" + to_string_dec_int(beep_squelch, 4) + "db]");
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
} else {
button_beep_squelch.set_style(&Styles::white);
button_beep_squelch.set_text("[ beep OFF ]");
}
}
void GlassView::manage_beep_audio() {
if (beep_enabled) {
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
} else {
baseband::request_beep_stop();
audio::output::stop();
}
}
void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power) {
if (mode == LOOKING_GLASS_SINGLEPASS) {
// <20MHz spectrum mode
@@ -173,6 +203,8 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
// we actually need SCREEN_W (240) of those bins
for (uint8_t bin = 0; bin < bin_length; bin++) {
get_max_power(spectrum, bin, max_power);
if (max_power > range_max_power)
range_max_power = max_power;
// process dc spike if enable
if (bin == 119) {
uint8_t next_max_power = 0;
@@ -184,14 +216,21 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
}
}
// process actual bin
if (process_bins(&max_power) == true)
if (process_bins(&max_power)) {
int8_t power = map(range_max_power, 0, 255, -100, 20);
if (power >= beep_squelch) {
baseband::request_audio_beep(map(range_max_power, 0, 256, 400, 2600), 24000, 250);
}
range_max_power = 0;
return; // new line signaled, return
}
}
if (mode != LOOKING_GLASS_SINGLEPASS) {
f_center += looking_glass_step;
retune();
} else
} else {
baseband::spectrum_streaming_start();
}
}
void GlassView::on_hide() {
@@ -327,13 +366,15 @@ GlassView::GlassView(
&field_lna,
&field_vga,
&field_range,
&steps_config,
//&steps_config,
&scan_type,
&view_config,
&level_integration,
&field_volume,
&filter_config,
&field_rf_amp,
&range_presets,
&button_beep_squelch,
&field_marker,
&field_trigger,
&button_jump,
@@ -370,12 +411,12 @@ GlassView::GlassView(
};
};
steps_config.on_change = [this](size_t, OptionsField::value_t v) {
/*steps_config.on_change = [this](size_t, OptionsField::value_t v) {
field_frequency_min.set_step(v);
field_frequency_max.set_step(v);
steps = v;
};
steps_config.set_selected_index(0); // 1 Mhz step.
steps_config.set_selected_index(0); // 1 Mhz step.*/
scan_type.on_change = [this](size_t, OptionsField::value_t v) {
mode = v;
@@ -497,6 +538,27 @@ GlassView::GlassView(
receiver_model.set_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
receiver_model.set_squelch_level(0);
receiver_model.enable();
button_beep_squelch.on_select = [this](ButtonWithEncoder& button) {
(void)button;
beep_enabled = 1 - beep_enabled;
manage_beep_audio();
update_display_beep();
};
button_beep_squelch.on_change = [this]() {
int new_beep_squelch = beep_squelch + button_beep_squelch.get_encoder_delta();
if (new_beep_squelch < -100)
new_beep_squelch = -100;
if (new_beep_squelch > 20)
new_beep_squelch = 20;
beep_squelch = new_beep_squelch;
button_beep_squelch.set_encoder_delta(0);
update_display_beep();
};
manage_beep_audio();
update_display_beep();
}
uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
@@ -510,7 +572,7 @@ void GlassView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // def
void GlassView::load_presets() {
File presets_file;
auto error = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
auto error = presets_file.open(looking_glass_dir / u"PRESETS.TXT");
presets_db.clear();
// Add the "Manual" entry.
@@ -85,6 +85,8 @@ class GlassView : public View {
uint8_t live_frequency_view = 0; // Spectrum
uint8_t live_frequency_integrate = 3; // Default (3 * old value + new_value) / 4
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
int32_t beep_squelch = 20; // range from -100 to +20, >=20 disabled
bool beep_enabled = false; // activate on bip button click
app_settings::SettingsManager settings_{
"rx_glass"sv,
app_settings::Mode::RX,
@@ -98,6 +100,8 @@ class GlassView : public View {
{"freq_view"sv, &live_frequency_view},
{"freq_integrate"sv, &live_frequency_integrate},
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
{"beep_squelch"sv, &beep_squelch},
{"beep_enabled"sv, &beep_enabled},
}};
struct preset_entry {
@@ -106,7 +110,10 @@ class GlassView : public View {
std::string label{};
};
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
std::vector<preset_entry> presets_db{};
void manage_beep_audio();
void update_display_beep();
void update_min(int32_t v);
void update_max(int32_t v);
void update_range_field();
@@ -153,6 +160,8 @@ class GlassView : public View {
int32_t steps = 1;
bool locked_range = false;
uint8_t range_max_power = 0;
uint8_t range_max_power_counter = 0;
uint8_t max_power = 0;
rf::Frequency max_freq_hold = 0;
rf::Frequency last_max_freq = 0;
@@ -166,7 +175,8 @@ class GlassView : public View {
{{0, 1 * 16}, "RANGE: FILTER: AMP:", Color::light_grey()},
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz RXIQCAL", Color::light_grey()},
{{0, 4 * 16}, "RES: STEP:", Color::light_grey()}};
//{{0, 4 * 16}, "RES: STEPS:", Color::light_grey()}};
{{0, 4 * 16}, "RES: VOL:", Color::light_grey()}};
NumberField field_frequency_min{
{4 * 8, 0 * 16},
@@ -206,9 +216,13 @@ class GlassView : public View {
OptionsField range_presets{
{7 * 8, 2 * 16},
20,
10,
{}};
ButtonWithEncoder button_beep_squelch{
{18 * 8, 2 * 16 + 4, 12 * 8, 1 * 8},
""};
TextField field_marker{
{7 * 8, 3 * 16, 9 * 8, 16},
""};
@@ -228,7 +242,10 @@ class GlassView : public View {
2,
' '};
OptionsField steps_config{
AudioVolumeField field_volume{
{13 * 8, 4 * 16}};
/*OptionsField steps_config{
{13 * 8, 4 * 16},
3,
{
@@ -238,7 +255,7 @@ class GlassView : public View {
{"100", 100},
{"250", 250},
{"500", 500},
}};
}};*/
OptionsField scan_type{
{17 * 8, 4 * 16},
+3 -3
View File
@@ -130,9 +130,9 @@ void MicTXView::set_tx(bool enable) {
portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming
} else {
if (transmitting && rogerbeep_enabled) {
baseband::request_beep(); // Transmit the roger beep
transmitting = false; // And flag the end of the transmission so ...
} else { // (if roger beep was enabled, this will be executed after the beep ends transmitting.
baseband::request_roger_beep(); // Transmit the roger beep
transmitting = false; // Flag the end of the transmission (transmitter will be disabled after the beep)
} else {
transmitting = false;
configure_baseband();
transmitter_model.disable();
+5 -4
View File
@@ -36,6 +36,7 @@
#include "string_format.hpp"
#include "ui_fileman.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include <unistd.h>
#include <fstream>
@@ -130,7 +131,7 @@ void PlaylistView::open_file(bool prompt_save) {
}
auto open_view = nav_.push<FileLoadView>(".PPL");
open_view->push_dir(u"PLAYLIST");
open_view->push_dir(playlist_dir);
open_view->on_changed = [this](fs::path new_file_path) {
on_file_changed(new_file_path);
};
@@ -169,7 +170,7 @@ void PlaylistView::save_file(bool show_dialogs) {
void PlaylistView::add_entry(fs::path&& path) {
if (playlist_path_.empty()) {
playlist_path_ = next_filename_matching_pattern(u"/PLAYLIST/PLAY_????.PPL");
playlist_path_ = next_filename_matching_pattern(playlist_dir / u"PLAY_????.PPL");
// Hack around focus getting called by ctor before parent is set.
if (parent())
@@ -387,7 +388,7 @@ PlaylistView::PlaylistView(
&waterfall,
});
ensure_directory(u"PLAYLIST");
ensure_directory(playlist_dir);
waterfall.show_audio_spectrum_view(false);
field_frequency.set_value(transmitter_model.target_frequency());
@@ -410,7 +411,7 @@ PlaylistView::PlaylistView(
if (is_active())
return;
auto open_view = nav_.push<FileLoadView>(".C*");
open_view->push_dir(u"CAPTURES");
open_view->push_dir(captures_dir);
open_view->on_changed = [this](fs::path path) {
add_entry(std::move(path));
};
+4 -4
View File
@@ -337,7 +337,7 @@ ReconView::ReconView(NavigationView& nav)
// set record View
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"AUTO_AUDIO", u"AUDIO",
u"AUTO_AUDIO", audio_dir,
RecordView::FileType::WAV, 4096, 4);
record_view->set_filename_date_frequency(true);
record_view->set_auto_trim(false);
@@ -1170,18 +1170,18 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
if (new_mod == SPEC_MODULATION) {
if (persistent_memory::recon_repeat_recorded()) {
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"RECON_REPEAT.C16", u"CAPTURES",
u"RECON_REPEAT.C16", captures_dir,
RecordView::FileType::RawS16, 16384, 3);
record_view->set_filename_as_is(true);
} else {
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"AUTO_RAW", u"CAPTURES",
u"AUTO_RAW", captures_dir,
RecordView::FileType::RawS16, 16384, 3);
record_view->set_filename_date_frequency(true);
}
} else {
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"AUTO_AUDIO", u"AUDIO",
u"AUTO_AUDIO", audio_dir,
RecordView::FileType::WAV, 4096, 4);
record_view->set_filename_date_frequency(true);
}
+1 -1
View File
@@ -38,6 +38,7 @@
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "file.hpp"
#include "file_path.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "ui_recon_settings.hpp"
@@ -181,7 +182,6 @@ class ReconView : public View {
const std::filesystem::path repeat_rec_file = u"RECON_REPEAT.C16";
const std::filesystem::path repeat_rec_meta = u"RECON_REPEAT.TXT";
const std::filesystem::path repeat_rec_path = u"CAPTURES";
const size_t repeat_read_size{16384};
const size_t repeat_buffer_count{3};
int8_t repeat_cur_rep = 0;
@@ -30,6 +30,7 @@
#include "freqman_db.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
using namespace std;
using namespace portapack;
+5 -4
View File
@@ -32,6 +32,7 @@
#include "ui_receiver.hpp"
#include "ui_textentry.hpp"
#include "utility.hpp"
#include "file_path.hpp"
using namespace portapack;
namespace fs = std::filesystem;
@@ -246,7 +247,7 @@ RemoteEntryEditView::RemoteEntryEditView(
field_path.on_select = [this, &nav](TextField&) {
auto open_view = nav.push<FileLoadView>(".C*");
open_view->push_dir(u"CAPTURES");
open_view->push_dir(captures_dir);
open_view->on_changed = [this](fs::path path) {
load_path(std::move(path));
refresh_ui();
@@ -355,7 +356,7 @@ RemoteView::RemoteView(
Dim waterfall_height = waterfall_bottom - waterfall_top;
waterfall.set_parent_rect({0, waterfall_top, screen_width, waterfall_height});
ensure_directory(u"REMOTES");
ensure_directory(remotes_dir);
// Load the previously loaded remote if exists.
if (!load_remote(settings_.remote_path))
@@ -527,7 +528,7 @@ void RemoteView::new_remote() {
void RemoteView::open_remote() {
auto open_view = nav_.push<FileLoadView>(".REM");
open_view->push_dir(u"REMOTES");
open_view->push_dir(remotes_dir);
open_view->on_changed = [this](fs::path path) {
save_remote();
load_remote(std::move(path));
@@ -538,7 +539,7 @@ void RemoteView::open_remote() {
void RemoteView::init_remote() {
model_ = {"<Unnamed Remote>", {}};
reset_buttons();
set_remote_path(next_filename_matching_pattern(u"/REMOTES/REMOTE_????.REM"));
set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM"));
set_needs_save(false);
if (remote_path_.empty())
+1
View File
@@ -26,6 +26,7 @@
#include "optional.hpp"
#include "ui_fileman.hpp"
#include "ui_freqman.hpp"
#include "file_path.hpp"
using namespace portapack;
namespace fs = std::filesystem;
+8 -7
View File
@@ -41,6 +41,7 @@ using namespace lpc43xx;
using namespace portapack;
#include "file.hpp"
#include "file_path.hpp"
namespace fs = std::filesystem;
#include "string_format.hpp"
@@ -571,17 +572,17 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) {
File pmem_flag_file_handle;
if (v) {
if (fs::file_exists(PMEM_FILEFLAG)) {
if (fs::file_exists(settings_dir / PMEM_FILEFLAG)) {
text_pmem_status.set("P.Mem flag file present.");
} else {
auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG);
auto error = pmem_flag_file_handle.create(settings_dir / PMEM_FILEFLAG);
if (error)
text_pmem_status.set("Error creating P.Mem File!");
else
text_pmem_status.set("P.Mem flag file created.");
}
} else {
auto result = delete_file(PMEM_FILEFLAG);
auto result = delete_file(settings_dir / PMEM_FILEFLAG);
if (result.code() != FR_OK)
text_pmem_status.set("Error deleting P.Mem flag!");
else
@@ -717,10 +718,10 @@ AppSettingsView::AppSettingsView(
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
ensure_directory(SETTINGS_DIR);
ensure_directory(settings_dir);
for (const auto& entry : std::filesystem::directory_iterator(SETTINGS_DIR, u"*.ini")) {
auto path = (std::filesystem::path)SETTINGS_DIR / entry.path();
for (const auto& entry : std::filesystem::directory_iterator(settings_dir, u"*.ini")) {
auto path = settings_dir / entry.path();
menu_view.add_item({path.filename().string().substr(0, 26),
ui::Color::dark_cyan(),
@@ -858,7 +859,7 @@ void SettingsMenuView::on_populate() {
{"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push<SetRadioView>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push<SetSDCardView>(); }},
{"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push<SetUIView>(); }},
{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push<SetQRCodeView>(); }},
//{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push<SetQRCodeView>(); }},
{"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetFakeBrightnessView>(); }},
{"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetMenuColorView>(); }},
});
+14 -48
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -24,6 +25,7 @@
#include "baseband_api.hpp"
#include "audio.hpp"
#include "app_settings.hpp"
#include "file_path.hpp"
#include "portapack.hpp"
#include <cstring>
@@ -70,14 +72,19 @@ SondeView::SondeView(NavigationView& nav)
geopos.set_read_only(true);
check_beep.set_value(beep);
check_beep.on_select = [this](Checkbox&, bool v) {
beep = v;
if (beep)
baseband::request_audio_beep(1000, 24000, 60); // 1khz tone for 60ms to acknowledge enablement
};
check_log.set_value(logging);
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
};
check_crc.set_value(use_crc);
check_crc.on_select = [this](Checkbox&, bool v) {
use_crc = v;
};
@@ -86,17 +93,18 @@ SondeView::SondeView(NavigationView& nav)
// QR code with geo URI
button_see_qr.on_select = [this, &nav](Button&) {
nav.push<QRCodeView>(geo_uri);
std::string geo_uri = "geo:" + to_string_decimal(geopos.lat(), 5) + "," + to_string_decimal(geopos.lon(), 5); // 5 decimal digits for ~1 meter accuracy
nav.push<QRCodeView>(geo_uri.data());
};
button_see_map.on_select = [this, &nav](Button&) {
geomap_view_ = nav.push<GeoMapView>(
sonde_id,
gps_info.alt,
geopos.altitude(),
GeoPos::alt_unit::METERS,
GeoPos::spd_unit::HIDDEN,
gps_info.lat,
gps_info.lon,
geopos.lat(),
geopos.lon(),
999); // set a dummy heading out of range to draw a cross...probably not ideal?
nav.set_on_pop([this]() {
geomap_view_ = nullptr;
@@ -105,7 +113,7 @@ SondeView::SondeView(NavigationView& nav)
logger = std::make_unique<SondeLogger>();
if (logger)
logger->append(LOG_ROOT_DIR "/SONDE.TXT");
logger->append(logs_dir / u"SONDE.TXT");
audio::output::start();
@@ -142,51 +150,9 @@ void SondeView::focus() {
field_frequency.focus();
}
// used to convert float to character pointer, since unfortunately function like
// sprintf and c_str aren't supported.
char* SondeView::float_to_char(float x, char* p) {
char* s = p + 9; // go to end of buffer
uint16_t decimals; // variable to store the decimals
int units; // variable to store the units (part to left of decimal place)
if (x < 0) { // take care of negative numbers
decimals = (int)(x * -100000) % 100000; // make 1000 for 3 decimals etc.
units = (int)(-1 * x);
} else { // positive numbers
decimals = (int)(x * 100000) % 100000;
units = (int)x;
}
// TODO: more elegant solution (loop?)
*--s = (decimals % 10) + '0';
decimals /= 10;
*--s = (decimals % 10) + '0';
decimals /= 10;
*--s = (decimals % 10) + '0';
decimals /= 10;
*--s = (decimals % 10) + '0';
decimals /= 10;
*--s = (decimals % 10) + '0';
*--s = '.';
while (units > 0) {
*--s = (units % 10) + '0';
units /= 10;
}
if (x < 0) *--s = '-'; // unary minus sign for negative numbers
return s;
}
void SondeView::on_packet(const sonde::Packet& packet) {
if (!use_crc || packet.crc_ok()) // euquiq: Reject bad packet if crc is on
{
char buffer_lat[10] = {};
char buffer_lon[10] = {};
strcpy(geo_uri, "geo:");
strcat(geo_uri, float_to_char(gps_info.lat, buffer_lat));
strcat(geo_uri, ",");
strcat(geo_uri, float_to_char(gps_info.lon, buffer_lon));
text_signature.set(packet.type_string());
sonde_id = packet.serial_number(); // used also as tag on the geomap
@@ -220,7 +186,7 @@ void SondeView::on_packet(const sonde::Packet& packet) {
}
if (beep) {
baseband::request_beep();
baseband::request_rssi_beep();
}
}
}
+11 -7
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -74,15 +75,19 @@ class SondeView : public View {
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_sonde", app_settings::Mode::RX};
std::unique_ptr<SondeLogger> logger{};
bool beep{false};
bool logging{false};
bool use_crc{false};
bool beep{false};
app_settings::SettingsManager settings_{
"rx_sonde",
app_settings::Mode::RX,
{
{"beep"sv, &beep},
{"logging"sv, &logging},
{"use_crc"sv, &use_crc},
}};
char geo_uri[32] = {};
std::unique_ptr<SondeLogger> logger{};
sonde::GPS_data gps_info{};
sonde::temp_humid temp_humid_info{};
@@ -201,7 +206,6 @@ class SondeView : public View {
void on_gps(const GPSPosDataMessage* msg);
void on_orientation(const OrientationDataMessage* msg);
void on_packet(const sonde::Packet& packet);
char* float_to_char(float x, char* p);
};
} /* namespace ui */
+1 -1
View File
@@ -38,7 +38,7 @@
class TestLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+2 -1
View File
@@ -27,6 +27,7 @@
#include "event_m0.hpp"
#include "file_reader.hpp"
#include "portapack.hpp"
#include "file_path.hpp"
#include <cstring>
@@ -142,7 +143,7 @@ WhipCalcView::WhipCalcView(NavigationView& nav)
void WhipCalcView::load_antenna_db() {
File antennas_file;
auto error = antennas_file.open("/WHIPCALC/ANTENNAS.TXT");
auto error = antennas_file.open(whipcalc_dir / u"ANTENNAS.TXT");
if (error)
return;
+19 -2
View File
@@ -428,8 +428,25 @@ void replay_stop() {
send_message(&message);
}
void request_beep() {
RequestSignalMessage message{RequestSignalMessage::Signal::BeepRequest};
void request_beep(RequestSignalMessage::Signal beep_type) {
RequestSignalMessage message{beep_type};
send_message(&message);
}
void request_roger_beep() {
request_beep(RequestSignalMessage::Signal::RogerBeepRequest);
}
void request_rssi_beep() {
request_beep(RequestSignalMessage::Signal::RSSIBeepRequest);
}
void request_beep_stop() {
request_beep(RequestSignalMessage::Signal::BeepStopRequest);
}
void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms) {
AudioBeepMessage message{freq, sample_rate, duration_ms};
send_message(&message);
}
+5 -1
View File
@@ -89,7 +89,11 @@ void set_siggen_tone(const uint32_t tone);
void set_siggen_config(const uint32_t bw, const uint32_t shape, const uint32_t duration);
void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bool update, int32_t bw);
void set_subghzd_config(uint8_t modulation, uint32_t sampling_rate);
void request_beep();
void request_roger_beep();
void request_rssi_beep();
void request_beep_stop();
void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms);
void run_image(const portapack::spi_flash::image_tag_t image_tag);
void run_prepared_image(const uint32_t m4_code);
+5 -4
View File
@@ -23,10 +23,11 @@
#include "database.hpp"
#include "file.hpp"
#include "file_path.hpp"
#include <cstring>
int database::retrieve_mid_record(MidDBRecord* record, std::string search_term) {
file_path = "AIS/mids.db";
file_path = ais_dir / u"mids.db";
index_item_length = 4;
record_length = 32;
@@ -36,7 +37,7 @@ int database::retrieve_mid_record(MidDBRecord* record, std::string search_term)
}
int database::retrieve_airline_record(AirlinesDBRecord* record, std::string search_term) {
file_path = "ADSB/airlines.db";
file_path = adsb_dir / u"airlines.db";
index_item_length = 4;
record_length = 64;
@@ -46,7 +47,7 @@ int database::retrieve_airline_record(AirlinesDBRecord* record, std::string sear
}
int database::retrieve_aircraft_record(AircraftDBRecord* record, std::string search_term) {
file_path = "ADSB/icao24.db";
file_path = adsb_dir / u"icao24.db";
index_item_length = 7;
record_length = 146;
@@ -55,7 +56,7 @@ int database::retrieve_aircraft_record(AircraftDBRecord* record, std::string sea
return (result);
}
int database::retrieve_record(std::string file_path, int index_item_length, int record_length, void* record, std::string search_term) {
int database::retrieve_record(std::filesystem::path file_path, int index_item_length, int record_length, void* record, std::string search_term) {
if (search_term.empty())
return DATABASE_RECORD_NOT_FOUND;
+4 -4
View File
@@ -61,9 +61,9 @@ class database {
int retrieve_aircraft_record(AircraftDBRecord* record, std::string search_term);
private:
std::string file_path = ""; // path inclusing filename
int index_item_length = 0; // length of index item
int record_length = 0; // length of record
std::filesystem::path file_path = ""; // path including filename
int index_item_length = 0; // length of index item
int record_length = 0; // length of record
File db_file{};
int number_of_records = 0;
@@ -74,7 +74,7 @@ class database {
int result = 0;
int retrieve_record(std::string file_path, int index_item_length, int record_length, void* record, std::string search_term);
int retrieve_record(std::filesystem::path file_path, int index_item_length, int record_length, void* record, std::string search_term);
};
#endif /*__DATABASE_H__*/
+2 -2
View File
@@ -32,6 +32,7 @@
#include "string_format.hpp"
#include "ui_styles.hpp"
#include "irq_controls.hpp"
#include "file_path.hpp"
using namespace ui;
@@ -266,7 +267,6 @@ bool stack_dump() {
bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag) {
Painter painter;
std::string debug_dir = "DEBUG";
std::filesystem::path filename{};
File dump_file{};
bool error;
@@ -277,7 +277,7 @@ bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag) {
bool data_found{false};
ensure_directory(debug_dir);
filename = next_filename_matching_pattern(debug_dir + "/" + (stack_flag ? "STACK" : "MEMORY") + "_DUMP_????.TXT");
filename = next_filename_matching_pattern(debug_dir + (stack_flag ? u"/STACK" : u"/MEMORY") + u"_DUMP_????.TXT");
error = filename.empty();
if (!error)
error = dump_file.create(filename) != 0;
+2 -1
View File
@@ -29,6 +29,7 @@
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
using namespace portapack;
using namespace modems;
@@ -84,7 +85,7 @@ AFSKRxView::AFSKRxView(NavigationView& nav)
logger = std::make_unique<AFSKLogger>();
if (logger)
logger->append(LOG_ROOT_DIR "/AFSK.TXT");
logger->append(logs_dir / u"AFSK.TXT");
// Auto-configure modem for LCR RX (will be removed later)
baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false);
+1 -1
View File
@@ -40,7 +40,7 @@ namespace ui::external_app::afsk_rx {
class AFSKLogger {
public:
Optional<File::Error> append(const std::string& filename) {
Optional<File::Error> append(const std::filesystem::path& filename) {
return log_file.append(filename);
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_audio_test.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::audio_test {
void initialize_app(ui::NavigationView& nav) {
nav.push<AudioTestView>();
}
} // namespace ui::external_app::audio_test
extern "C" {
__attribute__((section(".external_app.app_audio_test.application_information"), used)) application_information_t _application_information_audio_test = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::audio_test::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Audio Test",
/*.bitmap_data = */ {
0x00,
0x00,
0x40,
0x10,
0x60,
0x20,
0x70,
0x44,
0x78,
0x48,
0x7F,
0x91,
0x7F,
0x92,
0x7F,
0x92,
0x7F,
0x92,
0x7F,
0x92,
0x7F,
0x92,
0x7F,
0x91,
0x78,
0x48,
0x70,
0x44,
0x60,
0x20,
0x40,
0x10,
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_audio_test.hpp"
#include "baseband_api.hpp"
#include "audio.hpp"
#include "portapack.hpp"
using namespace portapack;
namespace ui {
AudioTestView::AudioTestView(NavigationView& nav)
: nav_{nav} {
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too
add_children({&labels,
&options_sample_rate,
&field_frequency,
&options_step,
&field_duration,
&field_volume,
&toggle_speaker});
audio::set_rate(audio::Rate::Hz_24000);
options_sample_rate.on_change = [this](size_t, int32_t v) {
switch (v) {
case 12000:
audio::set_rate(audio::Rate::Hz_12000);
break;
case 24000:
audio::set_rate(audio::Rate::Hz_24000);
break;
case 48000:
audio::set_rate(audio::Rate::Hz_48000);
break;
}
field_frequency.set_range(v / 128, v / 2);
update_audio_beep();
};
options_sample_rate.set_selected_index(0, 1);
field_frequency.on_change = [this](int32_t) {
update_audio_beep();
};
field_frequency.set_value(1000);
options_step.on_change = [this](size_t, int32_t v) {
field_frequency.set_step(v);
};
options_step.set_by_value(100);
field_duration.on_change = [this](int32_t v) {
(void)v;
update_audio_beep();
};
field_duration.set_value(100);
toggle_speaker.on_change = [this](bool v) {
beep = v;
update_audio_beep();
};
field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first
field_volume.set_value(80);
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
}
AudioTestView::~AudioTestView() {
receiver_model.disable();
baseband::shutdown();
audio::output::stop();
}
void AudioTestView::focus() {
toggle_speaker.focus();
}
void AudioTestView::update_audio_beep() {
if (beep)
baseband::request_audio_beep(field_frequency.value(), options_sample_rate.selected_index_value(), field_duration.value());
else
baseband::request_beep_stop();
}
} /* namespace ui */
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_AUDIO_TEST_H__
#define __UI_AUDIO_TEST_H__
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
namespace ui {
class AudioTestView : public View {
public:
AudioTestView(NavigationView& nav);
~AudioTestView();
AudioTestView(const AudioTestView& other) = delete;
AudioTestView& operator=(const AudioTestView& other) = delete;
void focus() override;
void update_audio_beep();
std::string title() const override { return "Audio Test"; };
private:
NavigationView& nav_;
bool beep{false};
Labels labels{
{{7 * 8, 3 * 16}, "Audio Beep Test", Color::light_grey()},
{{0 * 8, 6 * 16}, "Sample Rate (Hz):", Color::light_grey()},
{{25 * 8, 7 * 16}, "Step:", Color::light_grey()},
{{0 * 8, 8 * 16}, "Frequency (Hz):", Color::light_grey()},
{{0 * 8, 10 * 16}, "Duration (ms):", Color::light_grey()},
{{25 * 8, 10 * 16}, "0=con", Color::light_grey()},
{{0 * 8, 12 * 16}, "Volume:", Color::light_grey()}};
OptionsField options_sample_rate{
{18 * 8, 6 * 16},
5,
{{"24000", 24000},
{"48000", 48000},
{"12000", 12000}}};
OptionsField options_step{
{26 * 8, 8 * 16},
4,
{{" 1", 1},
{" 10", 10},
{" 100", 100},
{"1000", 1000}}};
NumberField field_frequency{
{18 * 8, 8 * 16},
5,
{},
100,
' ',
true};
NumberField field_duration{
{18 * 8, 10 * 16},
5,
{0, 60000},
50,
' ',
true};
AudioVolumeField field_volume{
{21 * 8, 12 * 16}};
ImageToggle toggle_speaker{
{21 * 8, 14 * 16, 2 * 8, 1 * 16},
&bitmap_icon_speaker_mute,
&bitmap_icon_speaker,
Color::light_grey(),
Color::dark_grey(),
Color::green(),
Color::dark_grey()};
};
} /* namespace ui */
#endif /*__UI_AUDIO_TEST_H__*/
+11
View File
@@ -67,6 +67,15 @@ set(EXTCPPSRC
external/extsensors/main.cpp
external/extsensors/ui_extsensors.cpp
external/extsensors/ui_extsensors.hpp
#foxhunt
external/foxhunt/main.cpp
external/foxhunt/ui_foxhunt_rx.cpp
external/foxhunt/ui_foxhunt_rx.hpp
#audio_test
external/audio_test/main.cpp
external/audio_test/ui_audio_test.cpp
)
set(EXTAPPLIST
@@ -86,4 +95,6 @@ set(EXTAPPLIST
keyfob
tetris
extsensors
foxhunt_rx
audio_test
)
+12
View File
@@ -39,6 +39,8 @@ MEMORY
ram_external_app_keyfob(rwx) : org = 0xADBD0000, len = 32k
ram_external_app_tetris(rwx) : org = 0xADBE0000, len = 32k
ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k
ram_external_app_foxhunt_rx(rwx) : org = 0xADC00000, len = 32k
ram_external_app_audio_test(rwx) : org = 0xADC10000, len = 32k
}
SECTIONS
@@ -139,6 +141,16 @@ SECTIONS
*(*ui*external_app*extsensors*);
} > ram_external_app_extsensors
.external_app_foxhunt_rx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_foxhunt_rx.application_information));
*(*ui*external_app*foxhunt_rx*);
} > ram_external_app_foxhunt_rx
.external_app_audio_test : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_audio_test.application_information));
*(*ui*external_app*audio_test*);
} > ram_external_app_audio_test
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 HTotoo
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_foxhunt_rx.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::foxhunt_rx {
void initialize_app(ui::NavigationView& nav) {
nav.push<FoxhuntRxView>();
}
} // namespace ui::external_app::foxhunt_rx
extern "C" {
__attribute__((section(".external_app.app_foxhunt_rx.application_information"), used)) application_information_t _application_information_foxhunt_rx = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::foxhunt_rx::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Fox hunt",
/*.bitmap_data = */ {
0x18,
0x18,
0x28,
0x14,
0x68,
0x16,
0x68,
0x16,
0xC8,
0x13,
0x88,
0x11,
0x04,
0x20,
0x24,
0x24,
0x22,
0x44,
0x01,
0x80,
0x06,
0x60,
0x98,
0x19,
0x20,
0x04,
0x40,
0x02,
0x80,
0x01,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.m4_app_tag = portapack::spi_flash::image_tag_am_audio */ {'P', 'A', 'M', 'A'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2024 HTotoo
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_foxhunt_rx.hpp"
#include "audio.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
using namespace modems;
using namespace ui;
namespace ui::external_app::foxhunt_rx {
void FoxhuntRxView::focus() {
field_frequency.focus();
}
FoxhuntRxView::FoxhuntRxView(NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
add_children({&rssi,
&field_rf_amp,
&field_lna,
&field_vga,
&field_volume,
&field_frequency,
&freq_stats_db,
&rssi_graph,
&geomap,
&clear_markers,
&add_current_marker});
clear_markers.on_select = [this](Button&) {
geomap.clear_markers();
};
add_current_marker.on_select = [this](Button&) {
GeoMarker tmp{my_lat, my_lon, my_orientation};
geomap.store_marker(tmp);
};
geomap.set_mode(DISPLAY);
geomap.set_manual_panning(false);
// geomap.set_enable_additional_zoom(true);
// geomap.set_hide_center_marker(true); //todo hide again after testing
geomap.set_focusable(true);
geomap.clear_markers();
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
field_frequency.set_step(100);
receiver_model.enable();
audio::output::start();
rssi_graph.set_nb_columns(64);
geomap.init();
}
FoxhuntRxView::~FoxhuntRxView() {
receiver_model.disable();
baseband::shutdown();
audio::output::stop();
}
void FoxhuntRxView::on_statistics_update(const ChannelStatistics& statistics) {
static int16_t last_max_db = -1000;
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
// refresh db
if (last_max_db != statistics.max_db) {
last_max_db = statistics.max_db;
freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db");
}
} /* on_statistic_updates */
void FoxhuntRxView::on_gps(const GPSPosDataMessage* msg) {
my_lat = msg->lat;
my_lon = msg->lon;
geomap.update_my_position(msg->lat, msg->lon, msg->altitude);
geomap.move(my_lon, my_lat);
geomap.set_dirty();
}
void FoxhuntRxView::on_orientation(const OrientationDataMessage* msg) {
my_orientation = msg->angle;
geomap.set_angle(msg->angle);
geomap.update_my_orientation(msg->angle, true);
}
} // namespace ui::external_app::foxhunt_rx
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2024 HTotoo
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_FOXHUNT_RX_H__
#define __UI_FOXHUNT_RX_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_geomap.hpp"
#include "ui_freq_field.hpp"
#include "ui_record_view.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "log_file.hpp"
#include "utility.hpp"
using namespace ui;
namespace ui::external_app::foxhunt_rx {
class FoxhuntRxView : public View {
public:
FoxhuntRxView(NavigationView& nav);
~FoxhuntRxView();
void focus() override;
std::string title() const override { return "Fox hunt"; };
private:
NavigationView& nav_;
RxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"rx_foxhunt", app_settings::Mode::RX};
RFAmpField field_rf_amp{
{13 * 8, 0 * 16}};
LNAGainField field_lna{
{15 * 8, 0 * 16}};
VGAGainField field_vga{
{18 * 8, 0 * 16}};
RSSI rssi{
{21 * 8, 0, 6 * 8, 4}};
AudioVolumeField field_volume{
{28 * 8, 0 * 16}};
RxFrequencyField field_frequency{
{0 * 8, 0 * 16},
nav_};
// Power: -XXX db
Text freq_stats_db{
{0 * 8, 2 * 16 + 4, 14 * 8, 14},
};
RSSIGraph rssi_graph{
{0, 50, 240, 30},
};
Button clear_markers{
{10 * 8, 18, 8 * 8, 16},
LanguageHelper::currentMessages[LANG_CLEAR]};
Button add_current_marker{
{2, 18, 7 * 8, 16},
"Mark"};
GeoMap geomap{{0, 80, 240, 240}};
MessageHandlerRegistration message_handler_gps{
Message::ID::GPSPosData,
[this](Message* const p) {
const auto message = static_cast<const GPSPosDataMessage*>(p);
this->on_gps(message);
}};
MessageHandlerRegistration message_handler_orientation{
Message::ID::OrientationData,
[this](Message* const p) {
const auto message = static_cast<const OrientationDataMessage*>(p);
this->on_orientation(message);
}};
MessageHandlerRegistration message_handler_stats{
Message::ID::ChannelStatistics,
[this](const Message* const p) {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}};
float my_lat = 200;
float my_lon = 200;
uint16_t my_orientation = 400;
void on_gps(const GPSPosDataMessage* msg);
void on_orientation(const OrientationDataMessage* msg);
void on_statistics_update(const ChannelStatistics& statistics);
};
} // namespace ui::external_app::foxhunt_rx
#endif /*__UI_FOXHUNT_RX_H__*/
@@ -76,15 +76,15 @@ SpectrumPainterView::SpectrumPainterView(
transmitter_model.set_rf_amp(rf_amp);
};
input_image.on_input_avaliable = [this]() {
image_input_avaliable = true;
input_image.on_input_available = [this]() {
image_input_available = true;
};
button_play.on_select = [this](ImageButton&) {
if (tx_active == false) {
tx_mode = tab_view.selected();
if (tx_mode == 0 && image_input_avaliable == false)
if (tx_mode == 0 && image_input_available == false)
return;
/* By experimental test measurement, we got a good painted spectrum quality when selecting
a BW GUI App range from 100k ... 2M aprox. In that range , the best TX LPF filter = 1M75 (the min)
@@ -61,7 +61,7 @@ class SpectrumPainterView : public View {
app_settings::SettingsManager settings_{
"tx_painter", app_settings::Mode::TX};
bool image_input_avaliable{false};
bool image_input_available{false};
bool tx_active{false};
uint32_t tx_mode{0};
uint16_t tx_current_line{0};
@@ -28,6 +28,7 @@
#include "io_file.hpp"
#include "file.hpp"
#include "portapack_persistent_memory.hpp"
#include "file_path.hpp"
namespace ui::external_app::spainter {
@@ -39,15 +40,14 @@ SpectrumInputImageView::SpectrumInputImageView(NavigationView& nav) {
button_load_image.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".bmp");
constexpr auto data_directory = u"SPECTRUM";
ensure_directory(data_directory);
open_view->push_dir(data_directory);
ensure_directory(spectrum_dir);
open_view->push_dir(spectrum_dir);
open_view->on_changed = [this](std::filesystem::path new_file_path) {
this->file = new_file_path.string();
painted = false;
this->set_dirty();
this->on_input_avaliable();
this->on_input_available();
};
};
}
@@ -46,7 +46,7 @@ class SpectrumInputImageView : public View {
uint16_t get_height();
std::vector<uint8_t> get_line(uint16_t);
std::function<void()> on_input_avaliable{};
std::function<void()> on_input_available{};
private:
bool painted{false};
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "file_path.hpp"
#include "file.hpp"
const std::filesystem::path adsb_dir = u"ADSB";
const std::filesystem::path ais_dir = u"AIS";
const std::filesystem::path aprs_dir = u"APRS";
const std::filesystem::path audio_dir = u"AUDIO";
const std::filesystem::path blerx_dir = u"BLERX";
const std::filesystem::path bletx_dir = u"BLETX";
const std::filesystem::path captures_dir = u"CAPTURES";
const std::filesystem::path debug_dir = u"DEBUG";
const std::filesystem::path firmware_dir = u"FIRMWARE";
const std::filesystem::path freqman_dir = u"FREQMAN";
const std::filesystem::path logs_dir = u"LOGS";
const std::filesystem::path looking_glass_dir = u"LOOKINGGLASS";
const std::filesystem::path playlist_dir = u"PLAYLIST";
const std::filesystem::path remotes_dir = u"REMOTES";
const std::filesystem::path repeat_rec_path = u"CAPTURES";
const std::filesystem::path screenshots_dir = u"SCREENSHOTS";
const std::filesystem::path settings_dir = u"SETTINGS";
const std::filesystem::path spectrum_dir = u"SPECTRUM";
const std::filesystem::path splash_dir = u"SPLASH";
const std::filesystem::path sstv_dir = u"SSTV";
const std::filesystem::path wav_dir = u"WAV";
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __FILE_PATH_H__
#define __FILE_PATH_H__
#include "file.hpp"
extern const std::filesystem::path adsb_dir;
extern const std::filesystem::path ais_dir;
extern const std::filesystem::path aprs_dir;
extern const std::filesystem::path audio_dir;
extern const std::filesystem::path blerx_dir;
extern const std::filesystem::path bletx_dir;
extern const std::filesystem::path captures_dir;
extern const std::filesystem::path debug_dir;
extern const std::filesystem::path firmware_dir;
extern const std::filesystem::path freqman_dir;
extern const std::filesystem::path logs_dir;
extern const std::filesystem::path looking_glass_dir;
extern const std::filesystem::path playlist_dir;
extern const std::filesystem::path remotes_dir;
extern const std::filesystem::path repeat_rec_path;
extern const std::filesystem::path screenshots_dir;
extern const std::filesystem::path settings_dir;
extern const std::filesystem::path spectrum_dir;
extern const std::filesystem::path splash_dir;
extern const std::filesystem::path sstv_dir;
extern const std::filesystem::path wav_dir;
extern const std::filesystem::path whipcalc_dir;
#endif /* __FILE_PATH_H__ */
+1 -1
View File
@@ -29,6 +29,7 @@
#include "string_format.hpp"
#include "tone_key.hpp"
#include "utility.hpp"
#include "file_path.hpp"
#include <array>
#include <cctype>
@@ -37,7 +38,6 @@
namespace fs = std::filesystem;
const std::filesystem::path freqman_dir{u"/FREQMAN"};
const std::filesystem::path freqman_extension{u".TXT"};
// NB: Don't include UI headers to keep this code unit testable.
-1
View File
@@ -36,7 +36,6 @@
#include <vector>
/* Defined in freqman_db.cpp */
extern const std::filesystem::path freqman_dir;
extern const std::filesystem::path freqman_extension;
using freqman_index_t = uint8_t;
-2
View File
@@ -27,8 +27,6 @@
#include "file.hpp"
#include "rtc_time.hpp"
#define LOG_ROOT_DIR "LOGS"
class LogFile {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
+3 -2
View File
@@ -34,6 +34,7 @@ using namespace portapack;
#include "complex.hpp"
#include "ui_styles.hpp"
#include "ui_font_fixed_5x8.hpp"
#include "file_path.hpp"
namespace ui {
@@ -447,7 +448,7 @@ void GeoMap::move(const float lon, const float lat) {
}
bool GeoMap::init() {
auto result = map_file.open("ADSB/world_map.bin");
auto result = map_file.open(adsb_dir / u"world_map.bin");
map_opened = !result.is_valid();
if (map_opened) {
@@ -613,7 +614,7 @@ void GeoMapView::focus() {
geopos.focus();
if (!geomap.map_file_opened())
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT);
nav_.display_modal("No map", "No world_map.bin file in\n/" + adsb_dir.string() + "/ directory", ABORT);
}
void GeoMapView::update_my_position(float lat, float lon, int32_t altitude) {
+9 -33
View File
@@ -59,43 +59,19 @@ void QRCodeImage::paint(Painter& painter) {
// The structure to manage the QR code
QRCode qrcode;
// Either small or large QR code can be shown..
int qr_version = 10;
if (portapack::persistent_memory::show_bigger_qr_code()) { // show large QR code
int qr_version = 2;
// Allocate a chunk of memory to store the QR code
uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)];
// Allocate a chunk of memory to store the QR code
uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)];
qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_);
qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_);
display.fill_rectangle(Rect(57, 65, 126, 127), Color::white());
display.fill_rectangle(Rect(10, 30, 220, 220), Color::white());
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
display.fill_rectangle(Rect(20 + (x * 8), 40 + (y * 8), 8, 8), Color::black());
}
}
}
}
else { // show small QR code
int qr_version = 10;
// Allocate a chunk of memory to store the QR code
uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)];
qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_);
display.fill_rectangle(Rect(92, 97, 63, 63), Color::white());
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
display.draw_pixel(Point(95 + x, 100 + y), Color::black());
}
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
display.fill_rectangle(Rect(63 + (x * 2), 71 + (y * 2), 2, 2), Color::black());
}
}
}
+4 -3
View File
@@ -106,6 +106,7 @@
#include "file.hpp"
#include "file_reader.hpp"
#include "png_writer.hpp"
#include "file_path.hpp"
using portapack::receiver_model;
using portapack::transmitter_model;
@@ -473,8 +474,8 @@ void SystemStatusView::on_bias_tee() {
}
void SystemStatusView::on_camera() {
ensure_directory("SCREENSHOTS");
auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG");
ensure_directory(screenshots_dir);
auto path = next_filename_matching_pattern(screenshots_dir / u"SCR_????.PNG");
if (path.empty())
return;
@@ -535,7 +536,7 @@ void SystemStatusView::rtc_battery_workaround() {
}
}
} else {
ensure_directory(SETTINGS_DIR);
ensure_directory(settings_dir);
make_new_file(DATE_FILEFLAG);
year = 1980;
+5 -4
View File
@@ -44,6 +44,7 @@
#include "ui_flash_utility.hpp"
#include "untar.hpp"
#include "ui_widget.hpp"
#include "file_path.hpp"
#include "ui_navigation.hpp"
#include "usb_serial_shell_filesystem.hpp"
@@ -167,8 +168,8 @@ static void cmd_screenshot(BaseSequentialStream* chp, int argc, char* argv[]) {
(void)argc;
(void)argv;
ensure_directory("SCREENSHOTS");
auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG");
ensure_directory(screenshots_dir);
auto path = next_filename_matching_pattern(screenshots_dir / u"SCR_????.PNG");
if (path.empty())
return;
@@ -1037,9 +1038,9 @@ static void cmd_settingsreset(BaseSequentialStream* chp, int argc, char* argv[])
if (!nav) return;
nav->home(true); // to exit all running apps
for (const auto& entry : std::filesystem::directory_iterator(SETTINGS_DIR, u"*.ini")) {
for (const auto& entry : std::filesystem::directory_iterator(settings_dir, u"*.ini")) {
if (std::filesystem::is_regular_file(entry.status())) {
std::filesystem::path pth = SETTINGS_DIR;
std::filesystem::path pth = settings_dir;
pth += u"/" + entry.path();
chprintf(chp, pth.string().c_str());
chprintf(chp, "\r\n");
+6 -1
View File
@@ -609,7 +609,6 @@ set(MODE_CPPSRC
)
DeclareTargets(PNRR nrfrx)
### Jammer
set(MODE_CPPSRC
@@ -645,6 +644,12 @@ set(MODE_CPPSRC
)
DeclareTargets(PTST test)
### Audio Beep
set(MODE_CPPSRC
proc_audio_beep.cpp
)
DeclareTargets(PABP audio_beep)
### HackRF "factory" firmware
+47
View File
@@ -25,9 +25,11 @@
#include <cstdint>
#include <cstddef>
#include <array>
#include <cstring>
#include "hal.h"
#include "gpdma.hpp"
#include "tone_gen.hpp"
using namespace lpc43xx;
@@ -36,6 +38,8 @@ using namespace lpc43xx;
namespace audio {
namespace dma {
ToneGen tone_gen{};
constexpr uint32_t gpdma_ahb_master_peripheral = 1;
constexpr uint32_t gpdma_ahb_master_memory = 0;
constexpr uint32_t gpdma_ahb_master_lli_fetch = 0;
@@ -145,9 +149,14 @@ static volatile const gpdma::channel::LLI* tx_next_lli = nullptr;
static volatile const gpdma::channel::LLI* rx_next_lli = nullptr;
static bool single_tx_buffer = false;
static uint32_t beep_duration_downcounter = 0;
static void tx_transfer_complete() {
tx_next_lli = gpdma_channel_i2s0_tx.next_lli();
if (beep_duration_downcounter != 0)
if (--beep_duration_downcounter == 0)
beep_stop();
}
static void tx_error() {
@@ -229,6 +238,44 @@ void shrink_tx_buffer(bool shrink) {
lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[1]);
}
void beep_start(uint32_t freq, uint32_t sample_rate, uint32_t beep_duration_ms) {
// Prevent divide-by-0
if (freq == 0 || sample_rate == 0)
return;
// Fill entire buffer with sine waves
tone_gen.configure_beep(freq, sample_rate);
for (size_t i = 0; i < buffer_samples; i++)
buffer_tx[i].left = buffer_tx[i].right = tone_gen.process_beep();
// Try to adjust DMA transfer count to align with full sine waves for a better tone
float samples_per_sine_wave = float(sample_rate) / freq;
uint32_t sine_waves_per_buffer = buffer_samples / samples_per_sine_wave;
size_t sample_count = (sine_waves_per_buffer == 0) ? buffer_samples : sine_waves_per_buffer * samples_per_sine_wave + 0.5;
// Use single larger transfer buffer with sample count determined above
lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[0]);
lli_tx_loop[0].control = control_tx(sample_count * sizeof(sample_t));
// Convert duration ms to number of buffers to send before stopping
// NB: beep_duration_ms==0 means beep continuously until stopped
uint32_t beep_interrupt_count = beep_duration_ms * sample_rate / (1000 * sample_count);
if ((beep_duration_ms != 0) && (beep_interrupt_count == 0))
beep_interrupt_count = 1;
beep_duration_downcounter = beep_interrupt_count;
}
void beep_stop() {
// Clear audio DMA buffer
memset(&buffer_tx, 0, buffer_bytes);
// Restore DMA linked list to use multiple smaller buffers
lli_tx_loop[0].control = control_tx(transfer_bytes);
if (!single_tx_buffer && (transfers_per_buffer > 1)) {
lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[1]);
}
}
buffer_t tx_empty_buffer() {
const auto next_lli = tx_next_lli;
if (next_lli) {
+2
View File
@@ -47,6 +47,8 @@ void init_audio_in();
void init_audio_out();
void disable();
void shrink_tx_buffer(bool shrink);
void beep_start(uint32_t freq, uint32_t sample_rate, uint32_t beep_duration_ms);
void beep_stop();
audio::buffer_t tx_empty_buffer();
audio::buffer_t rx_empty_buffer();
+3
View File
@@ -27,6 +27,7 @@
#include "portapack_dma.hpp"
#include "gpdma.hpp"
#include "audio_dma.hpp"
static void init() {
// Audio DMA initialization was moved to baseband proc's that actually use DMA audio, to save memory.
@@ -65,6 +66,8 @@ void __late_init(void) {
void _default_exit(void) {
// TODO: Is this complete?
audio::dma::disable();
nvicDisableVector(DMA_IRQn);
chSysDisable();
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_audio_beep.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
AudioBeepProcessor::AudioBeepProcessor() {
}
void AudioBeepProcessor::execute(const buffer_c8_t& buffer) {
(void)buffer;
}
void AudioBeepProcessor::on_message(const Message* const msg) {
switch (msg->id) {
case Message::ID::RequestSignal:
on_signal_message(*reinterpret_cast<const RequestSignalMessage*>(msg));
break;
case Message::ID::AudioBeep:
on_beep_message(*reinterpret_cast<const AudioBeepMessage*>(msg));
break;
default:
break;
}
}
void AudioBeepProcessor::on_signal_message(const RequestSignalMessage& message) {
if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) {
audio::dma::beep_stop();
}
}
void AudioBeepProcessor::on_beep_message(const AudioBeepMessage& message) {
audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms);
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<AudioBeepProcessor>()};
event_dispatcher.run();
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_AUDIO_BEEP_H__
#define __PROC_AUDIO_BEEP_H__
#include "baseband_processor.hpp"
#include "message.hpp"
#define AUDIO_SAMPLE_RATE 24000
class AudioBeepProcessor : public BasebandProcessor {
public:
AudioBeepProcessor();
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg);
private:
void on_signal_message(const RequestSignalMessage& message);
void on_beep_message(const AudioBeepMessage& message);
};
#endif /*__PROC_AUDIO_BEEP_H__*/
+21 -2
View File
@@ -21,7 +21,7 @@
*/
#include "proc_capture.hpp"
#include "audio_dma.hpp"
#include "dsp_fir_taps.hpp"
#include "event_m4.hpp"
#include "utility.hpp"
@@ -55,6 +55,16 @@ void CaptureProcessor::execute(const buffer_c8_t& buffer) {
}
}
void CaptureProcessor::on_signal_message(const RequestSignalMessage& message) {
if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) {
audio::dma::beep_stop();
}
}
void CaptureProcessor::on_beep_message(const AudioBeepMessage& message) {
audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms);
}
void CaptureProcessor::on_message(const Message* const message) {
switch (message->id) {
case Message::ID::UpdateSpectrum:
@@ -70,6 +80,14 @@ void CaptureProcessor::on_message(const Message* const message) {
capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));
break;
case Message::ID::RequestSignal:
on_signal_message(*reinterpret_cast<const RequestSignalMessage*>(message));
break;
case Message::ID::AudioBeep:
on_beep_message(*reinterpret_cast<const AudioBeepMessage*>(message));
break;
default:
break;
}
@@ -152,7 +170,8 @@ void CaptureProcessor::capture_config(const CaptureConfigMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<CaptureProcessor>()};
event_dispatcher.run();
return 0;
}
}
+4
View File
@@ -30,6 +30,7 @@
#include "dsp_decimate.hpp"
#include "spectrum_collector.hpp"
#include "stream_input.hpp"
#include "message.hpp"
#include <array>
#include <memory>
@@ -92,6 +93,9 @@ class CaptureProcessor : public BasebandProcessor {
void on_message(const Message* const message) override;
private:
void on_signal_message(const RequestSignalMessage& message);
void on_beep_message(const AudioBeepMessage& message);
size_t baseband_fs = 3072000; // aka: sample_rate
static constexpr auto spectrum_rate_hz = 50.0f;
+1 -1
View File
@@ -155,7 +155,7 @@ void MicTXProcessor::on_message(const Message* const msg) {
break;
case Message::ID::RequestSignal:
if (request_message.signal == RequestSignalMessage::Signal::BeepRequest) {
if (request_message.signal == RequestSignalMessage::Signal::RogerBeepRequest) {
beep_index = 0;
beep_timer = 0;
play_beep = true;
+22 -62
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -26,16 +27,12 @@
#include "event_m4.hpp"
#include "audio_output.hpp"
#include "audio_dma.hpp"
SondeProcessor::SondeProcessor() {
decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps);
audio_output.configure(false);
tone_gen.configure(BEEP_BASE_FREQ, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
baseband_thread.start();
}
@@ -55,48 +52,20 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) {
clock_recovery_fsk_4800(mf.get_output());
}
}
if (pitch_rssi_enabled) {
if (beep_play) {
// if we let the buffer underrun, for some reason
// once it starts looping it ignores zero (silence)
// samples, so we need to keep feeding the buffer
// and not be able to take advantage of the circular
// buffer loop:
// beep_play = false;
generate_beep();
}
if (silence_play) {
// silence_play = false;
generate_silence();
}
}
}
void SondeProcessor::on_message(const Message* const msg) {
switch (msg->id) {
case Message::ID::RequestSignal:
if ((*reinterpret_cast<const RequestSignalMessage*>(msg)).signal == RequestSignalMessage::Signal::BeepRequest) {
float rssi_ratio = (float)last_rssi / (float)RSSI_CEILING;
int beep_duration = 0;
on_signal_message(*reinterpret_cast<const RequestSignalMessage*>(msg));
break;
if (rssi_ratio <= PROPORTIONAL_BEEP_THRES) {
beep_duration = BEEP_MIN_DURATION;
} else if (rssi_ratio < 1) {
beep_duration = (int)rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
} else {
beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
play_beep();
chThdSleepMilliseconds(beep_duration);
stop_beep();
}
case Message::ID::AudioBeep:
on_beep_message(*reinterpret_cast<const AudioBeepMessage*>(msg));
break;
case Message::ID::PitchRSSIConfigure:
pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(msg));
on_pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(msg));
break;
default:
@@ -104,41 +73,32 @@ void SondeProcessor::on_message(const Message* const msg) {
}
}
void SondeProcessor::play_beep() {
beep_play = true;
silence_play = false;
}
void SondeProcessor::on_signal_message(const RequestSignalMessage& message) {
if (message.signal == RequestSignalMessage::Signal::RSSIBeepRequest) {
float rssi_ratio = (float)last_rssi / RSSI_CEILING;
uint32_t beep_duration = 0;
void SondeProcessor::stop_beep() {
beep_play = false;
silence_play = true;
}
if (rssi_ratio <= PROPORTIONAL_BEEP_THRES) {
beep_duration = BEEP_MIN_DURATION;
} else if (rssi_ratio < 1) {
beep_duration = rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
} else {
beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
void SondeProcessor::generate_beep() {
// here we let the samples be created using the ToneGen class:
for (uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = (int16_t)((tone_gen.process(0) >> 16) & 0x0000FFFF);
audio::dma::beep_start(beep_freq, DEFAULT_AUDIO_SAMPLE_RATE, beep_duration);
}
audio_output.write(audio_buffer);
}
void SondeProcessor::generate_silence() {
for (uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = 0;
}
audio_output.write(audio_buffer);
void SondeProcessor::on_beep_message(const AudioBeepMessage& message) {
audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms);
}
void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
void SondeProcessor::on_pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
pitch_rssi_enabled = message.enabled;
uint32_t freq = (int)((float)message.rssi * (float)RSSI_PITCH_WEIGHT + (float)BEEP_BASE_FREQ);
beep_freq = message.rssi * RSSI_PITCH_WEIGHT + BEEP_BASE_FREQ;
last_rssi = message.rssi;
tone_gen.configure(freq, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
}
int main() {
+10 -34
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2014 zilog80
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -88,9 +89,6 @@
#include "message.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_output.hpp"
#include "tone_gen.hpp"
#include "buffer.hpp"
#include <cstdint>
@@ -99,11 +97,13 @@
#define BEEP_MIN_DURATION 60
#define BEEP_DURATION_RANGE 100
#define BEEP_BASE_FREQ 200
#define BEEP_BASE_FREQ 400 // Lowest audible freq for some PortaPack speakers
#define BEEP_MAX_FREQ 8000 // Highest audible freq for some PortaPack speakers
#define BEEP_SIMPLE_FREQ 1000
#define RSSI_CEILING 1000
#define PROPORTIONAL_BEEP_THRES 0.8
#define RSSI_PITCH_WEIGHT 0.5
#define AUDIO_SAMPLE_RATE 24000
#define RSSI_PITCH_WEIGHT (float(BEEP_MAX_FREQ - BEEP_BASE_FREQ) / RSSI_CEILING)
#define DEFAULT_AUDIO_SAMPLE_RATE 24000
class SondeProcessor : public BasebandProcessor {
public:
@@ -115,21 +115,10 @@ class SondeProcessor : public BasebandProcessor {
private:
static constexpr size_t baseband_fs = 2457600;
std::array<int16_t, 32> audio{};
const buffer_s16_t audio_buffer{
(int16_t*)audio.data(),
sizeof(audio) / sizeof(int16_t)};
AudioOutput audio_output{};
bool beep_play{false};
bool silence_play{false};
bool pitch_rssi_enabled{false};
uint32_t last_rssi{0};
ToneGen tone_gen{};
uint32_t beep_freq{0};
std::array<complex16_t, 512> dst{};
const buffer_c16_t dst_buffer{
@@ -181,22 +170,9 @@ class SondeProcessor : public BasebandProcessor {
baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false};
RSSIThread rssi_thread{};
void play_beep();
void stop_beep();
/**
* Used for filling the audio buffer with the waveform
* generated by the ToneGen class:
*
*/
void generate_beep();
/**
* Used for filling the audio buffer with silence:
*/
void generate_silence();
void pitch_rssi_config(const PitchRSSIConfigureMessage& message);
void on_signal_message(const RequestSignalMessage& message);
void on_beep_message(const AudioBeepMessage& message);
void on_pitch_rssi_config(const PitchRSSIConfigureMessage& message);
};
#endif /*__PROC_ERT_H__*/
+23 -1
View File
@@ -60,7 +60,30 @@ void WidebandSpectrum::execute(const buffer_c8_t& buffer) {
}
}
void WidebandSpectrum::on_signal_message(const RequestSignalMessage& message) {
if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) {
audio::dma::beep_stop();
}
}
void WidebandSpectrum::on_beep_message(const AudioBeepMessage& message) {
audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms);
}
void WidebandSpectrum::on_message(const Message* const msg) {
switch (msg->id) {
case Message::ID::RequestSignal:
on_signal_message(*reinterpret_cast<const RequestSignalMessage*>(msg));
return;
case Message::ID::AudioBeep:
on_beep_message(*reinterpret_cast<const AudioBeepMessage*>(msg));
return;
default:
break;
}
const WidebandSpectrumConfigMessage message = *reinterpret_cast<const WidebandSpectrumConfigMessage*>(msg);
switch (msg->id) {
@@ -84,7 +107,6 @@ void WidebandSpectrum::on_message(const Message* const msg) {
int main() {
audio::dma::init_audio_out(); // for AudioRX app (enables audio output while this baseband image is running)
EventDispatcher event_dispatcher{std::make_unique<WidebandSpectrum>()};
event_dispatcher.run();
return 0;
@@ -43,6 +43,9 @@ class WidebandSpectrum : public BasebandProcessor {
bool configured = false;
size_t baseband_fs = 20000000;
void on_beep_message(const AudioBeepMessage& message);
void on_signal_message(const RequestSignalMessage& message);
SpectrumCollector channel_spectrum{};
std::array<complex16_t, 256> spectrum{};
+15 -54
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -23,53 +24,25 @@
#include "tone_gen.hpp"
#include "sine_table_int8.hpp"
/*
int32_t ToneGen::tone_sine() {
// TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde
// Hoepfully we can manage without it , same as previous fw 1.3.1
int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000;
tone_phase_ += delta_;
// Functions for audio beep (used by Sonde RSSI)
void ToneGen::configure_beep(const uint32_t freq, const uint32_t sample_rate) {
f_delta_ = (float)(freq * sizeof(sine_table_i8)) / sample_rate;
f_tone_phase_ = 0.0;
return tone_sample;
// For higher frequencies, start at sine peak to handle case of freq=sample_rate/2;
// we don't want to sample the sine wave only when it's crossing 0!
// There is still an amplitude issue though depending on magnitude of selected sine sample deltas.
if (f_delta_ >= sizeof(sine_table_i8) / 4)
f_tone_phase_ = sizeof(sine_table_i8) / 4;
}
*/
int32_t ToneGen::tone_square() {
// TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde
int32_t tone_sample = 0;
if (tone_phase_ < (UINT32_MAX / 2)) {
tone_sample = INT32_MAX;
} else {
tone_sample = INT32_MIN;
}
tone_phase_ += delta_;
int16_t ToneGen::process_beep() {
int16_t tone_sample = sine_table_i8[(uint32_t)f_tone_phase_ & 0xFF] * 256;
f_tone_phase_ += f_delta_;
return tone_sample;
}
/*
void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) {
// Confirmed ! It is not working well in the fw 1.4.4 Mic App , CTCSS generation, (but added for Sonde App)
// I Think it should be deleted or modified but not use it as it is in Mic App .
delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24);
delta_ = delta;
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = sine;
}
*/
void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) {
// TODO : Added for Sonde App. We keep it by now to avoid compile errors, but it needs to be reviewed in Sonde
delta_ = (uint8_t)((freq * sizeof(sine_table_i8)) / sample_rate);
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = tone_type;
}
// ----Original available core SW code from fw 1.3.1 , Working also well in Mic App CTCSS Gen from fw 1.4.0 onwards
// Original direct-look-up synthesis algorithm with Fractional delta phase. It is OK
@@ -78,6 +51,7 @@ void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const
void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) {
delta_ = delta;
tone_phase_ = 0;
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
}
@@ -90,17 +64,4 @@ int32_t ToneGen::process(const int32_t sample_in) {
tone_phase_ += delta_;
return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_);
}
// -------------------------------------------------------------
int32_t ToneGen::process_square(const int32_t sample_in) {
// TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde
if (!delta_)
return sample_in;
int32_t tone_sample = 0;
tone_sample = tone_square();
return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_);
}
}
+7 -25
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -28,40 +29,21 @@
class ToneGen {
public:
enum tone_type { sine,
square }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not.
/*ToneGen(const size_t sample_rate
) : sample_rate_ { sample_rate }
{};*/
void configure(const uint32_t delta, const float tone_mix_weight);
void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate);
int32_t process(const int32_t sample_in);
int32_t process_square(const int32_t sample_in);
void configure_beep(const uint32_t freq, const uint32_t sample_rate);
int16_t process_beep();
private:
tone_type current_tone_type_{sine};
float input_mix_weight_{1};
float tone_mix_weight_{0};
float f_delta_{0.0};
float f_tone_phase_{0.0};
uint32_t delta_{0};
uint32_t tone_phase_{0};
// uint8_t delta_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not.
// uint8_t tone_phase_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not.
/**
* Generator function which selects every other sample from the reference sine waveform to the output sample:
*/
int32_t tone_sine(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not.
/**
* Generator function for square waves:
*/
int32_t tone_square(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not.
};
#endif /* __TONE_GEN_H__ */
+21 -3
View File
@@ -121,6 +121,7 @@ class Message {
GPSPosData = 63,
OrientationData = 64,
EnvironmentData = 65,
AudioBeep = 66,
MAX
};
@@ -133,7 +134,7 @@ class Message {
};
struct RSSIStatistics {
uint16_t accumulator{0};
uint32_t accumulator{0};
uint8_t min{0};
uint8_t max{0};
uint16_t count{0};
@@ -1165,8 +1166,10 @@ class RequestSignalMessage : public Message {
public:
enum class Signal : char {
FillRequest = 1,
BeepRequest = 2,
Squelched = 3
RogerBeepRequest = 2,
RSSIBeepRequest = 3,
BeepStopRequest = 4,
Squelched = 5,
};
constexpr RequestSignalMessage(
@@ -1361,4 +1364,19 @@ class EnvironmentDataMessage : public Message {
uint16_t light = 0; // lux
};
class AudioBeepMessage : public Message {
public:
constexpr AudioBeepMessage(
uint32_t freq = 1000,
uint32_t sample_rate = 24000,
uint32_t duration_ms = 100)
: Message{ID::AudioBeep},
freq{freq},
sample_rate{sample_rate},
duration_ms{duration_ms} {
}
uint32_t freq = 1000;
uint32_t sample_rate = 24000;
uint32_t duration_ms = 100;
};
#endif /*__MESSAGE_H__*/
@@ -37,6 +37,7 @@
#include "ui_flash_utility.hpp"
#include "utility.hpp"
#include "rtc_time.hpp"
#include "file_path.hpp"
#include <algorithm>
#include <string>
@@ -1105,14 +1106,14 @@ void set_menu_color(Color v) {
// PMem to sdcard settings
bool should_use_sdcard_for_pmem() {
return std::filesystem::file_exists(PMEM_FILEFLAG);
return std::filesystem::file_exists(settings_dir / PMEM_FILEFLAG);
}
int save_persistent_settings_to_file() {
File outfile;
ensure_directory(SETTINGS_DIR);
auto error = outfile.create(PMEM_SETTING_FILE);
ensure_directory(settings_dir);
auto error = outfile.create(settings_dir / PMEM_SETTING_FILE);
if (error)
return false;
@@ -1122,7 +1123,7 @@ int save_persistent_settings_to_file() {
int load_persistent_settings_from_file() {
File infile;
auto error = infile.open(PMEM_SETTING_FILE);
auto error = infile.open(settings_dir / PMEM_SETTING_FILE);
if (error)
return false;
@@ -37,10 +37,10 @@
#include "ui.hpp"
// persistent memory from/to sdcard flag file
#define PMEM_FILEFLAG u"/SETTINGS/PMEM_FILEFLAG"
#define PMEM_FILEFLAG u"PMEM_FILEFLAG"
// persistent memory from/to sdcard flag file
#define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings"
#define PMEM_SETTING_FILE u"pmem_settings"
#define PMEM_SIZE_BYTES 256 // total amount of pmem space in bytes, including checksum
#define PMEM_SIZE_WORDS (PMEM_SIZE_BYTES / 4)
+1
View File
@@ -74,6 +74,7 @@ struct image_tag_t {
};
constexpr image_tag_t image_tag_none{0, 0, 0, 0};
constexpr image_tag_t image_tag_audio_beep{'P', 'A', 'B', 'P'};
constexpr image_tag_t image_tag_acars{'P', 'A', 'C', 'A'};
constexpr image_tag_t image_tag_adsb_rx{'P', 'A', 'D', 'R'};
constexpr image_tag_t image_tag_afsk_rx{'P', 'A', 'F', 'R'};
+1 -1
View File
@@ -523,7 +523,7 @@ class NewButton : public Widget {
protected:
virtual Style paint_style();
Color color_;
Color bg_color_{Color::light_grey()};
Color bg_color_{Color::grey()};
private:
std::string text_;
+6 -5
View File
@@ -1,5 +1,6 @@
f=460125000,d=CPDCW1 CH1
f=460175000,d=CPDCW2 CH2
f=460275000,d=CPDCW3 CH3
f=460325000,d=CPDCW4 CH4
f=460350000,d=CPDCW5 CH5
# Chicago Police City Wide Dispatch
f=460125000,d=Chicago PD CW1
f=460175000,d=Chicago PD CW2
f=460275000,d=Chicago PD CW3
f=460325000,d=Chicago PD CW4
f=460350000,d=Chicago PD CW5
+15
View File
@@ -0,0 +1,15 @@
# Common SSTV frequencies
# frequencies marked Active have more frequent transmissions.
f=3640000,d=SSTV 80M
f=7043000,d=SSTV 40M - Active
f=7170000,d=SSTV 40M - Active
f=10132000,d=SSTV 30M
f=14230000,d=SSTV 20M - Active
f=14233000,d=SSTV 20M - Active
f=14236000,d=SSTV 20M
f=14240000,d=SSTV 20M
f=21340000,d=SSTV 15M - Active
f=28680000,d=SSTV 10M - Active
f=50950000,d=SSTV 6M
f=145625000,d=SSTV 2M
f=433775000,d=SSTV 70CM
+25 -3
View File
@@ -5,13 +5,22 @@
# 433 MHz BAND
423,443,433 BAND
# AVIATION
108,137,AVIATION 108
108,118,AVIATION 108 NAVAIDS
118,137,AVIATION 118 VOICE
960,1215,AVIATION 960
1089,1091,ADS-B 1090
128,137,ACARS
# BROADCAST RADIO
87,108,FM BROADCAST
87,108,FM BROADCAST USA
76,108,FM BROADCAST BRAZIL
76,95,FM BROADCAST JAPAN
65,74,FM BROADCAST RUSSIA
# CITIZENS BAND RADIO
26,28,CITIZENS BAND RADIO
# COMMON PUBLIC SERVICE BANDS
150,160, PUBLIC SERVICE 155
450,470,PUBLIC SERVICE 460
769,775,PUBLIC SERVICE 770
# DECT
1879,1931,DECT
# FRS/GMRS
@@ -25,7 +34,12 @@
902,928,HAM 33-CM
1240,1300,HAM 23-CM
# KEYFOBS
260,500,315/433 MHz KEYFOBS
305,325,315 MHz KEYFOBS
380,400,390 MHz KEYFOBS
423,443,433 MHz KEYFOBS
858,878,868 MHz KEYFOBS
902,929,915 MHz KEYFOBS
# 260,500,315/433 MHz KEYFOBS
# LoRa
433,435,LoRa 443EU
863,870,LoRa 868EU
@@ -36,14 +50,22 @@
# MICS
140,380,MICS (VHF) AND MARINE
420,660,MICS (UHF)
169,172,MICS COMMON
# MULTI-USE RADIO SERVICE - MURS
151,155,MULTI-USE RADIO SRVS
# NOAA WEATHER RADIO
161,164,NOAA WEATHER RADIO
# PAGERS https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging
34,36,USA PAGERS 35
43,45,USA PAGERS 44
151,153,USA PAGERS 152
157,159,USA PAGERS 158
453,454,USA PAGERS 454
929,931,USA PAGERS 930
# RADIOSONDES
390,420,RADIOSONDES
# RAILROAD
159,162,RAILROAD
# WATER METERS
850,900,Water meters
902,928,ISM 900MHz