mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-14 04:27:39 +00:00
2
.github/workflows/past_version.txt
vendored
2
.github/workflows/past_version.txt
vendored
@@ -1 +1 @@
|
|||||||
v1.8.0
|
v1.9.0
|
||||||
|
2
.github/workflows/version.txt
vendored
2
.github/workflows/version.txt
vendored
@@ -1 +1 @@
|
|||||||
v1.9.0
|
v1.9.1
|
||||||
|
@@ -426,6 +426,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
|||||||
&options_sort,
|
&options_sort,
|
||||||
&label_found,
|
&label_found,
|
||||||
&text_found_count,
|
&text_found_count,
|
||||||
|
&check_serial_log,
|
||||||
&button_filter,
|
&button_filter,
|
||||||
&button_save_list,
|
&button_save_list,
|
||||||
&button_clear_list,
|
&button_clear_list,
|
||||||
@@ -436,7 +437,15 @@ BLERxView::BLERxView(NavigationView& nav)
|
|||||||
nav_.push<BleRecentEntryDetailView>(entry);
|
nav_.push<BleRecentEntryDetailView>(entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
check_serial_log.on_select = [this](Checkbox&, bool v) {
|
||||||
|
serial_logging = v;
|
||||||
|
if (v) {
|
||||||
usb_serial_thread = std::make_unique<UsbSerialThread>();
|
usb_serial_thread = std::make_unique<UsbSerialThread>();
|
||||||
|
} else {
|
||||||
|
usb_serial_thread.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
check_serial_log.set_value(serial_logging);
|
||||||
|
|
||||||
ensure_directory(find_packet_path);
|
ensure_directory(find_packet_path);
|
||||||
ensure_directory(log_packets_path);
|
ensure_directory(log_packets_path);
|
||||||
@@ -456,8 +465,6 @@ BLERxView::BLERxView(NavigationView& nav)
|
|||||||
|
|
||||||
logger = std::make_unique<BLELogger>();
|
logger = std::make_unique<BLELogger>();
|
||||||
|
|
||||||
check_log.set_value(logging);
|
|
||||||
|
|
||||||
check_log.on_select = [this](Checkbox&, bool v) {
|
check_log.on_select = [this](Checkbox&, bool v) {
|
||||||
str_log = "";
|
str_log = "";
|
||||||
logging = v;
|
logging = v;
|
||||||
@@ -468,6 +475,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
|||||||
"/BLELOG_" +
|
"/BLELOG_" +
|
||||||
to_string_timestamp(rtc_time::now()) + ".TXT");
|
to_string_timestamp(rtc_time::now()) + ".TXT");
|
||||||
};
|
};
|
||||||
|
check_log.set_value(logging);
|
||||||
|
|
||||||
button_save_list.on_select = [this, &nav](const ui::Button&) {
|
button_save_list.on_select = [this, &nav](const ui::Button&) {
|
||||||
listFileBuffer = "";
|
listFileBuffer = "";
|
||||||
@@ -723,8 +731,10 @@ void BLERxView::on_data(BlePacketData* packet) {
|
|||||||
logger->log_raw_data(str_console + "\r\n");
|
logger->log_raw_data(str_console + "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serial_logging) {
|
||||||
usb_serial_thread->serial_str = str_console + "\r\n";
|
usb_serial_thread->serial_str = str_console + "\r\n";
|
||||||
usb_serial_thread->str_ready = true;
|
usb_serial_thread->str_ready = true;
|
||||||
|
}
|
||||||
str_console = "";
|
str_console = "";
|
||||||
|
|
||||||
if (!searchList.empty()) {
|
if (!searchList.empty()) {
|
||||||
|
@@ -215,6 +215,7 @@ class BLERxView : public View {
|
|||||||
uint8_t sort_index{0};
|
uint8_t sort_index{0};
|
||||||
std::string filter{};
|
std::string filter{};
|
||||||
bool logging{false};
|
bool logging{false};
|
||||||
|
bool serial_logging{false};
|
||||||
|
|
||||||
bool name_enable{true};
|
bool name_enable{true};
|
||||||
app_settings::SettingsManager settings_{
|
app_settings::SettingsManager settings_{
|
||||||
@@ -225,6 +226,8 @@ class BLERxView : public View {
|
|||||||
{"sort_index"sv, &sort_index},
|
{"sort_index"sv, &sort_index},
|
||||||
{"filter"sv, &filter},
|
{"filter"sv, &filter},
|
||||||
{"log"sv, &logging},
|
{"log"sv, &logging},
|
||||||
|
// disabled to always start without USB serial activated until we can make it non blocking if not connected
|
||||||
|
// {"serial_log"sv, &serial_logging},
|
||||||
{"name"sv, &name_enable},
|
{"name"sv, &name_enable},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -320,6 +323,12 @@ class BLERxView : public View {
|
|||||||
{11 * 8, 3 * 16, 20 * 8, 16},
|
{11 * 8, 3 * 16, 20 * 8, 16},
|
||||||
"0/0"};
|
"0/0"};
|
||||||
|
|
||||||
|
Checkbox check_serial_log{
|
||||||
|
{17 * 8, 3 * 16 - 2},
|
||||||
|
7,
|
||||||
|
"USB Log",
|
||||||
|
true};
|
||||||
|
|
||||||
Console console{
|
Console console{
|
||||||
{0, 4 * 16, 240, 240}};
|
{0, 4 * 16, 240, 240}};
|
||||||
|
|
||||||
|
@@ -146,7 +146,7 @@ class ERTAppView : public View {
|
|||||||
static constexpr auto header_height = 1 * 16;
|
static constexpr auto header_height = 1 * 16;
|
||||||
|
|
||||||
RxFrequencyField field_frequency{
|
RxFrequencyField field_frequency{
|
||||||
{5 * 8, 0 * 16},
|
{0 * 8, 0 * 16},
|
||||||
nav_};
|
nav_};
|
||||||
|
|
||||||
RFAmpField field_rf_amp{
|
RFAmpField field_rf_amp{
|
||||||
|
@@ -176,12 +176,15 @@ void RegistersWidget::paint(Painter& painter) {
|
|||||||
|
|
||||||
void RegistersWidget::draw_legend(const Coord left, Painter& painter) {
|
void RegistersWidget::draw_legend(const Coord left, Painter& painter) {
|
||||||
const auto pos = screen_pos();
|
const auto pos = screen_pos();
|
||||||
|
const std::string spaces(config.legend_length(), ' ');
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < config.registers_per_page; i += config.registers_per_row()) {
|
||||||
|
uint32_t r = page_number * config.registers_per_page + i;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < config.registers_count; i += config.registers_per_row()) {
|
|
||||||
const Point offset{
|
const Point offset{
|
||||||
left, static_cast<int>((i / config.registers_per_row()) * row_height)};
|
left, static_cast<int>((i / config.registers_per_row()) * row_height)};
|
||||||
|
|
||||||
const auto text = to_string_hex(i, config.legend_length());
|
const auto text = (r >= config.registers_count) ? spaces : to_string_hex(r, config.legend_length());
|
||||||
painter.draw_string(
|
painter.draw_string(
|
||||||
pos + offset,
|
pos + offset,
|
||||||
style().invert(),
|
style().invert(),
|
||||||
@@ -193,15 +196,16 @@ void RegistersWidget::draw_values(
|
|||||||
const Coord left,
|
const Coord left,
|
||||||
Painter& painter) {
|
Painter& painter) {
|
||||||
const auto pos = screen_pos();
|
const auto pos = screen_pos();
|
||||||
|
const std::string spaces(config.value_length(), ' ');
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < config.registers_per_page; i++) {
|
||||||
|
uint32_t r = page_number * config.registers_per_page + i;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < config.registers_count; i++) {
|
|
||||||
const Point offset = {
|
const Point offset = {
|
||||||
static_cast<int>(left + config.legend_width() + 8 + (i % config.registers_per_row()) * (config.value_width() + 8)),
|
static_cast<int>(left + config.legend_width() + 8 + (i % config.registers_per_row()) * (config.value_width() + 8)),
|
||||||
static_cast<int>((i / config.registers_per_row()) * row_height)};
|
static_cast<int>((i / config.registers_per_row()) * row_height)};
|
||||||
|
|
||||||
const auto value = reg_read(i);
|
const auto text = (r >= config.registers_count) ? spaces : to_string_hex(reg_read(r), config.value_length());
|
||||||
|
|
||||||
const auto text = to_string_hex(value, config.value_length());
|
|
||||||
painter.draw_string(
|
painter.draw_string(
|
||||||
pos + offset,
|
pos + offset,
|
||||||
style(),
|
style(),
|
||||||
@@ -213,7 +217,7 @@ uint32_t RegistersWidget::reg_read(const uint32_t register_number) {
|
|||||||
if (register_number < config.registers_count) {
|
if (register_number < config.registers_count) {
|
||||||
switch (config.chip_type) {
|
switch (config.chip_type) {
|
||||||
case CT_PMEM:
|
case CT_PMEM:
|
||||||
return portapack::persistent_memory::pmem_data_word((page_number * config.registers_count + register_number) / 4) >> (register_number % 4 * 8);
|
return portapack::persistent_memory::pmem_data_word(register_number / 4) >> (register_number % 4 * 8);
|
||||||
case CT_RFFC5072:
|
case CT_RFFC5072:
|
||||||
return radio::debug::first_if::register_read(register_number);
|
return radio::debug::first_if::register_read(register_number);
|
||||||
case CT_MAX283X:
|
case CT_MAX283X:
|
||||||
@@ -272,6 +276,7 @@ RegistersView::RegistersView(
|
|||||||
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||||
|
|
||||||
registers_widget.set_parent_rect({0, 48, 240, 192});
|
registers_widget.set_parent_rect({0, 48, 240, 192});
|
||||||
|
registers_widget.set_page(0);
|
||||||
|
|
||||||
text_title.set_parent_rect({(240 - static_cast<int>(title.size()) * 8) / 2, 16,
|
text_title.set_parent_rect({(240 - static_cast<int>(title.size()) * 8) / 2, 16,
|
||||||
static_cast<int>(title.size()) * 8, 16});
|
static_cast<int>(title.size()) * 8, 16});
|
||||||
@@ -296,6 +301,13 @@ void RegistersView::focus() {
|
|||||||
button_done.focus();
|
button_done.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RegistersView::on_encoder(const EncoderEvent delta) {
|
||||||
|
registers_widget.set_page(std::max(0ul, std::min(registers_widget.page_count() - 1, registers_widget.page() + delta)));
|
||||||
|
registers_widget.update();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* ControlsSwitchesWidget ************************************************/
|
/* ControlsSwitchesWidget ************************************************/
|
||||||
|
|
||||||
void ControlsSwitchesWidget::on_show() {
|
void ControlsSwitchesWidget::on_show() {
|
||||||
@@ -429,10 +441,10 @@ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
|
|||||||
const char* max283x = hackrf_r9 ? "MAX2839" : "MAX2837";
|
const char* max283x = hackrf_r9 ? "MAX2839" : "MAX2837";
|
||||||
const char* si5351x = hackrf_r9 ? "Si5351A" : "Si5351C";
|
const char* si5351x = hackrf_r9 ? "Si5351A" : "Si5351C";
|
||||||
add_items({
|
add_items({
|
||||||
{"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 16}); }},
|
{"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }},
|
||||||
{max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push<RegistersView>(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 10}); }},
|
{max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push<RegistersView>(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }},
|
||||||
{si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 96, 8}); }},
|
{si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
|
||||||
{audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_bits()}); }},
|
{audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
|
||||||
});
|
});
|
||||||
set_max_rows(2); // allow wider buttons
|
set_max_rows(2); // allow wider buttons
|
||||||
}
|
}
|
||||||
@@ -504,8 +516,8 @@ void DebugMemoryDumpView::focus() {
|
|||||||
/* DebugPmemView *********************************************************/
|
/* DebugPmemView *********************************************************/
|
||||||
|
|
||||||
DebugPmemView::DebugPmemView(NavigationView& nav)
|
DebugPmemView::DebugPmemView(NavigationView& nav)
|
||||||
: registers_widget(RegistersWidgetConfig{CT_PMEM, page_size, 8}) {
|
: registers_widget(RegistersWidgetConfig{CT_PMEM, PMEM_SIZE_BYTES, page_size, 8}) {
|
||||||
add_children({&text_page, ®isters_widget, &text_checksum, &text_checksum2, &button_ok});
|
add_children({®isters_widget, &text_checksum, &text_checksum2, &button_ok});
|
||||||
|
|
||||||
registers_widget.set_parent_rect({0, 32, 240, 192});
|
registers_widget.set_parent_rect({0, 32, 240, 192});
|
||||||
|
|
||||||
@@ -532,7 +544,6 @@ void DebugPmemView::focus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugPmemView::update() {
|
void DebugPmemView::update() {
|
||||||
text_page.set(to_string_hex(registers_widget.page() * page_size, 2) + "+");
|
|
||||||
registers_widget.update();
|
registers_widget.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -142,6 +142,7 @@ typedef enum {
|
|||||||
struct RegistersWidgetConfig {
|
struct RegistersWidgetConfig {
|
||||||
chip_type_t chip_type;
|
chip_type_t chip_type;
|
||||||
uint32_t registers_count;
|
uint32_t registers_count;
|
||||||
|
uint32_t registers_per_page;
|
||||||
uint32_t register_bits;
|
uint32_t register_bits;
|
||||||
|
|
||||||
constexpr size_t legend_length() const {
|
constexpr size_t legend_length() const {
|
||||||
@@ -194,6 +195,7 @@ class RegistersWidget : public Widget {
|
|||||||
|
|
||||||
void set_page(int32_t value) { page_number = value; }
|
void set_page(int32_t value) { page_number = value; }
|
||||||
uint32_t page(void) { return page_number; }
|
uint32_t page(void) { return page_number; }
|
||||||
|
uint32_t page_count(void) { return (config.registers_count + config.registers_per_page - 1) / config.registers_per_page; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const RegistersWidgetConfig config;
|
const RegistersWidgetConfig config;
|
||||||
@@ -208,8 +210,8 @@ class RegistersWidget : public Widget {
|
|||||||
class RegistersView : public View {
|
class RegistersView : public View {
|
||||||
public:
|
public:
|
||||||
RegistersView(NavigationView& nav, const std::string& title, RegistersWidgetConfig&& config);
|
RegistersView(NavigationView& nav, const std::string& title, RegistersWidgetConfig&& config);
|
||||||
|
void focus() override;
|
||||||
void focus();
|
bool on_encoder(const EncoderEvent delta) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Text text_title{};
|
Text text_title{};
|
||||||
@@ -364,8 +366,6 @@ class DebugPmemView : public View {
|
|||||||
static constexpr uint8_t page_size{96}; // Must be multiply of 4 otherwise bit shifting for register view wont work properly
|
static constexpr uint8_t page_size{96}; // Must be multiply of 4 otherwise bit shifting for register view wont work properly
|
||||||
static constexpr uint8_t page_count{(portapack::memory::map::backup_ram.size() + page_size - 1) / page_size};
|
static constexpr uint8_t page_count{(portapack::memory::map::backup_ram.size() + page_size - 1) / page_size};
|
||||||
|
|
||||||
Text text_page{{16, 16, 208, 16}};
|
|
||||||
|
|
||||||
RegistersWidget registers_widget;
|
RegistersWidget registers_widget;
|
||||||
|
|
||||||
Text text_checksum{{16, 232, 208, 16}};
|
Text text_checksum{{16, 232, 208, 16}};
|
||||||
|
@@ -412,7 +412,8 @@ void FrequencyEditView::refresh_ui() {
|
|||||||
|
|
||||||
auto is_range = entry_.type == freqman_type::Range;
|
auto is_range = entry_.type == freqman_type::Range;
|
||||||
auto is_ham = entry_.type == freqman_type::HamRadio;
|
auto is_ham = entry_.type == freqman_type::HamRadio;
|
||||||
auto has_freq_b = is_range || is_ham;
|
auto is_repeater = entry_.type == freqman_type::Repeater;
|
||||||
|
auto has_freq_b = is_range || is_ham || is_repeater;
|
||||||
|
|
||||||
field_freq_b.set_style(has_freq_b ? &Styles::white : &Styles::grey);
|
field_freq_b.set_style(has_freq_b ? &Styles::white : &Styles::grey);
|
||||||
field_step.set_style(is_range ? &Styles::white : &Styles::grey);
|
field_step.set_style(is_range ? &Styles::white : &Styles::grey);
|
||||||
|
@@ -220,7 +220,8 @@ class FrequencyEditView : public View {
|
|||||||
{"Single", 0},
|
{"Single", 0},
|
||||||
{"Range", 1},
|
{"Range", 1},
|
||||||
{"HamRadio", 2},
|
{"HamRadio", 2},
|
||||||
{"Raw", 3},
|
{"Repeater", 3},
|
||||||
|
{"Raw", 4},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
FrequencyField field_freq_a{{13 * 8, 4 * 16}};
|
FrequencyField field_freq_a{{13 * 8, 4 * 16}};
|
||||||
|
@@ -22,13 +22,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_recon.hpp"
|
#include "ui_recon.hpp"
|
||||||
#include "ui_fileman.hpp"
|
|
||||||
#include "ui_freqman.hpp"
|
#include "ui_freqman.hpp"
|
||||||
#include "capture_app.hpp"
|
#include "capture_app.hpp"
|
||||||
#include "convert.hpp"
|
#include "convert.hpp"
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
#include "file_reader.hpp"
|
#include "file_reader.hpp"
|
||||||
#include "tone_key.hpp"
|
#include "tone_key.hpp"
|
||||||
|
#include "replay_app.hpp"
|
||||||
|
#include "string_format.hpp"
|
||||||
|
#include "ui_fileman.hpp"
|
||||||
|
#include "io_file.hpp"
|
||||||
|
#include "io_convert.hpp"
|
||||||
|
#include "oversample.hpp"
|
||||||
|
#include "baseband_api.hpp"
|
||||||
|
#include "metadata_file.hpp"
|
||||||
|
#include "portapack.hpp"
|
||||||
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
#include "replay_thread.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
using namespace tonekey;
|
using namespace tonekey;
|
||||||
@@ -37,6 +48,30 @@ namespace fs = std::filesystem;
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
void ReconView::reload_restart_recon() {
|
||||||
|
frequency_file_load();
|
||||||
|
if (frequency_list.size() > 0) {
|
||||||
|
if (fwd) {
|
||||||
|
button_dir.set_text("FW>");
|
||||||
|
} else {
|
||||||
|
button_dir.set_text("<RW");
|
||||||
|
}
|
||||||
|
recon_resume();
|
||||||
|
}
|
||||||
|
if (scanner_mode) {
|
||||||
|
file_name.set_style(&Styles::red);
|
||||||
|
button_scanner_mode.set_style(&Styles::red);
|
||||||
|
button_scanner_mode.set_text("SCAN");
|
||||||
|
} else {
|
||||||
|
file_name.set_style(&Styles::blue);
|
||||||
|
button_scanner_mode.set_style(&Styles::blue);
|
||||||
|
button_scanner_mode.set_text("RECON");
|
||||||
|
}
|
||||||
|
if (frequency_list.size() > FREQMAN_MAX_PER_FILE) {
|
||||||
|
file_name.set_style(&Styles::yellow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ReconView::check_update_ranges_from_current() {
|
void ReconView::check_update_ranges_from_current() {
|
||||||
if (frequency_list.size() && current_is_valid() && current_entry().type == freqman_type::Range) {
|
if (frequency_list.size() && current_is_valid() && current_entry().type == freqman_type::Range) {
|
||||||
if (update_ranges && !manual_mode) {
|
if (update_ranges && !manual_mode) {
|
||||||
@@ -75,8 +110,12 @@ void ReconView::recon_stop_recording() {
|
|||||||
button_audio_app.set_text("AUDIO");
|
button_audio_app.set_text("AUDIO");
|
||||||
button_audio_app.set_style(&Styles::white);
|
button_audio_app.set_style(&Styles::white);
|
||||||
record_view->stop();
|
record_view->stop();
|
||||||
button_config.set_style(&Styles::white); // disable config while recording as it's causing an IO error pop up at exit
|
button_config.set_style(&Styles::white);
|
||||||
is_recording = false;
|
is_recording = false;
|
||||||
|
// repeater mode
|
||||||
|
if (persistent_memory::recon_repeat_recorded()) {
|
||||||
|
start_repeat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +150,9 @@ void ReconView::update_description() {
|
|||||||
case freqman_type::HamRadio:
|
case freqman_type::HamRadio:
|
||||||
description = "H: ";
|
description = "H: ";
|
||||||
break;
|
break;
|
||||||
|
case freqman_type::Repeater:
|
||||||
|
description = "L: ";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
description = "S: ";
|
description = "S: ";
|
||||||
}
|
}
|
||||||
@@ -182,6 +224,7 @@ void ReconView::load_persisted_settings() {
|
|||||||
load_freqs = persistent_memory::recon_load_freqs();
|
load_freqs = persistent_memory::recon_load_freqs();
|
||||||
load_ranges = persistent_memory::recon_load_ranges();
|
load_ranges = persistent_memory::recon_load_ranges();
|
||||||
load_hamradios = persistent_memory::recon_load_hamradios();
|
load_hamradios = persistent_memory::recon_load_hamradios();
|
||||||
|
load_repeaters = persistent_memory::recon_load_repeaters();
|
||||||
update_ranges = persistent_memory::recon_update_ranges_when_recon();
|
update_ranges = persistent_memory::recon_update_ranges_when_recon();
|
||||||
auto_record_locked = persistent_memory::recon_auto_record_locked();
|
auto_record_locked = persistent_memory::recon_auto_record_locked();
|
||||||
}
|
}
|
||||||
@@ -275,9 +318,20 @@ ReconView::~ReconView() {
|
|||||||
ReconView::ReconView(NavigationView& nav)
|
ReconView::ReconView(NavigationView& nav)
|
||||||
: nav_{nav} {
|
: nav_{nav} {
|
||||||
chrono_start = chTimeNow();
|
chrono_start = chTimeNow();
|
||||||
|
|
||||||
|
tx_view.hidden(true);
|
||||||
|
|
||||||
|
// set record View
|
||||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||||
u"AUTO_AUDIO_", u"AUDIO",
|
u"AUTO_AUDIO", u"AUDIO",
|
||||||
RecordView::FileType::WAV, 4096, 4);
|
RecordView::FileType::WAV, 4096, 4);
|
||||||
|
record_view->set_filename_date_frequency(true);
|
||||||
|
record_view->set_auto_trim(false);
|
||||||
|
record_view->hidden(true);
|
||||||
|
record_view->on_error = [&nav](std::string message) {
|
||||||
|
nav.display_modal("Error", message);
|
||||||
|
};
|
||||||
|
|
||||||
add_children({&labels,
|
add_children({&labels,
|
||||||
&field_lna,
|
&field_lna,
|
||||||
&field_vga,
|
&field_vga,
|
||||||
@@ -314,13 +368,9 @@ ReconView::ReconView(NavigationView& nav)
|
|||||||
&button_restart,
|
&button_restart,
|
||||||
&button_mic_app,
|
&button_mic_app,
|
||||||
&button_remove,
|
&button_remove,
|
||||||
record_view.get()});
|
record_view.get(),
|
||||||
|
&progressbar,
|
||||||
record_view->hidden(true);
|
&tx_view});
|
||||||
record_view->set_filename_date_frequency(true);
|
|
||||||
record_view->on_error = [&nav](std::string message) {
|
|
||||||
nav.display_modal("Error", message);
|
|
||||||
};
|
|
||||||
|
|
||||||
def_step = 0;
|
def_step = 0;
|
||||||
load_persisted_settings();
|
load_persisted_settings();
|
||||||
@@ -566,27 +616,7 @@ ReconView::ReconView(NavigationView& nav)
|
|||||||
};
|
};
|
||||||
|
|
||||||
button_restart.on_select = [this](Button&) {
|
button_restart.on_select = [this](Button&) {
|
||||||
frequency_file_load();
|
reload_restart_recon();
|
||||||
if (frequency_list.size() > 0) {
|
|
||||||
if (fwd) {
|
|
||||||
button_dir.set_text("FW>");
|
|
||||||
} else {
|
|
||||||
button_dir.set_text("<RW");
|
|
||||||
}
|
|
||||||
recon_resume();
|
|
||||||
}
|
|
||||||
if (scanner_mode) {
|
|
||||||
file_name.set_style(&Styles::red);
|
|
||||||
button_scanner_mode.set_style(&Styles::red);
|
|
||||||
button_scanner_mode.set_text("SCAN");
|
|
||||||
} else {
|
|
||||||
file_name.set_style(&Styles::blue);
|
|
||||||
button_scanner_mode.set_style(&Styles::blue);
|
|
||||||
button_scanner_mode.set_text("RECON");
|
|
||||||
}
|
|
||||||
if (frequency_list.size() > FREQMAN_MAX_PER_FILE) {
|
|
||||||
file_name.set_style(&Styles::yellow);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
button_add.on_select = [this](ButtonWithEncoder&) {
|
button_add.on_select = [this](ButtonWithEncoder&) {
|
||||||
@@ -704,6 +734,9 @@ ReconView::ReconView(NavigationView& nav)
|
|||||||
change_mode(AM_MODULATION); // start on AM.
|
change_mode(AM_MODULATION); // start on AM.
|
||||||
field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector
|
field_mode.set_by_value(AM_MODULATION); // reflect the mode into the manual selector
|
||||||
|
|
||||||
|
// tx progress bar
|
||||||
|
progressbar.hidden(true);
|
||||||
|
|
||||||
if (filedelete) {
|
if (filedelete) {
|
||||||
delete_file(freq_file_path);
|
delete_file(freq_file_path);
|
||||||
}
|
}
|
||||||
@@ -741,7 +774,8 @@ void ReconView::frequency_file_load() {
|
|||||||
freqman_load_options options{
|
freqman_load_options options{
|
||||||
.load_freqs = load_freqs,
|
.load_freqs = load_freqs,
|
||||||
.load_ranges = load_ranges,
|
.load_ranges = load_ranges,
|
||||||
.load_hamradios = load_hamradios};
|
.load_hamradios = load_hamradios,
|
||||||
|
.load_repeaters = load_repeaters};
|
||||||
if (!load_freqman_file(file_input, frequency_list, options) || frequency_list.empty()) {
|
if (!load_freqman_file(file_input, frequency_list, options) || frequency_list.empty()) {
|
||||||
file_name.set_style(&Styles::red);
|
file_name.set_style(&Styles::red);
|
||||||
desc_cycle.set("...empty file...");
|
desc_cycle.set("...empty file...");
|
||||||
@@ -776,6 +810,12 @@ void ReconView::frequency_file_load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||||
|
if (recon_tx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_repeat_active())
|
||||||
|
return;
|
||||||
|
|
||||||
chrono_end = chTimeNow();
|
chrono_end = chTimeNow();
|
||||||
systime_t time_interval = chrono_end - chrono_start;
|
systime_t time_interval = chrono_end - chrono_start;
|
||||||
chrono_start = chrono_end;
|
chrono_start = chrono_end;
|
||||||
@@ -835,9 +875,9 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
|||||||
// contents of a possible recon_start_recording(), but not yet since it's only called once
|
// contents of a possible recon_start_recording(), but not yet since it's only called once
|
||||||
if (auto_record_locked && !is_recording) {
|
if (auto_record_locked && !is_recording) {
|
||||||
button_audio_app.set_style(&Styles::red);
|
button_audio_app.set_style(&Styles::red);
|
||||||
if (field_mode.selected_index_value() == SPEC_MODULATION)
|
if (field_mode.selected_index_value() == SPEC_MODULATION) {
|
||||||
button_audio_app.set_text("RAW REC");
|
button_audio_app.set_text("RAW REC");
|
||||||
else
|
} else
|
||||||
button_audio_app.set_text("WAV REC");
|
button_audio_app.set_text("WAV REC");
|
||||||
record_view->start();
|
record_view->start();
|
||||||
button_config.set_style(&Styles::light_grey); // disable config while recording as it's causing an IO error pop up at exit
|
button_config.set_style(&Styles::light_grey); // disable config while recording as it's causing an IO error pop up at exit
|
||||||
@@ -956,6 +996,26 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (current_entry().type == freqman_type::Repeater) {
|
||||||
|
// repeater is like single, we only listen on frequency_a and then jump to next entry
|
||||||
|
if ((fwd && stepper == 0) || stepper > 0) { // forward
|
||||||
|
current_index++;
|
||||||
|
entry_has_changed = true;
|
||||||
|
// looping
|
||||||
|
if ((uint32_t)current_index >= frequency_list.size()) {
|
||||||
|
has_looped = true;
|
||||||
|
current_index = 0;
|
||||||
|
}
|
||||||
|
} else if ((!fwd && stepper == 0) || stepper < 0) {
|
||||||
|
// reverse
|
||||||
|
current_index--;
|
||||||
|
entry_has_changed = true;
|
||||||
|
// if previous if under the list => go back from end
|
||||||
|
if (current_index < 0) {
|
||||||
|
has_looped = true;
|
||||||
|
current_index = frequency_list.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// set index to boundary if !continuous
|
// set index to boundary if !continuous
|
||||||
if (has_looped && !continuous) {
|
if (has_looped && !continuous) {
|
||||||
@@ -984,6 +1044,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
|||||||
if (entry_has_changed) {
|
if (entry_has_changed) {
|
||||||
timer = 0;
|
timer = 0;
|
||||||
switch (current_entry().type) {
|
switch (current_entry().type) {
|
||||||
|
case freqman_type::Repeater:
|
||||||
case freqman_type::Single:
|
case freqman_type::Single:
|
||||||
freq = current_entry().frequency_a;
|
freq = current_entry().frequency_a;
|
||||||
break;
|
break;
|
||||||
@@ -1017,7 +1078,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
|
|||||||
if (stepper > 0) stepper--;
|
if (stepper > 0) stepper--;
|
||||||
} // if( recon || stepper != 0 || index_stepper != 0 )
|
} // if( recon || stepper != 0 || index_stepper != 0 )
|
||||||
} // if (frequency_list.size() > 0 )
|
} // if (frequency_list.size() > 0 )
|
||||||
} /* on_statistic_updates */
|
} /* on_statistics_updates */
|
||||||
}
|
}
|
||||||
handle_retune();
|
handle_retune();
|
||||||
recon_redraw();
|
recon_redraw();
|
||||||
@@ -1080,28 +1141,39 @@ void ReconView::on_stepper_delta(int32_t v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t ReconView::change_mode(freqman_index_t new_mod) {
|
size_t ReconView::change_mode(freqman_index_t new_mod) {
|
||||||
|
if (recon_tx || is_repeat_active())
|
||||||
|
return 0;
|
||||||
field_mode.on_change = [this](size_t, OptionsField::value_t) {};
|
field_mode.on_change = [this](size_t, OptionsField::value_t) {};
|
||||||
field_bw.on_change = [this](size_t, OptionsField::value_t) {};
|
field_bw.on_change = [this](size_t, OptionsField::value_t) {};
|
||||||
recon_stop_recording();
|
recon_stop_recording();
|
||||||
|
if (record_view != nullptr) {
|
||||||
remove_child(record_view.get());
|
remove_child(record_view.get());
|
||||||
record_view.reset();
|
record_view.reset();
|
||||||
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",
|
||||||
|
RecordView::FileType::RawS16, 16384, 3);
|
||||||
|
record_view->set_filename_as_is(true);
|
||||||
|
} else if (new_mod == SPEC_MODULATION) {
|
||||||
audio::output::stop();
|
audio::output::stop();
|
||||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||||
u"AUTO_RAW_", u"CAPTURES",
|
u"AUTO_RAW", u"CAPTURES",
|
||||||
RecordView::FileType::RawS16, 16384, 3);
|
RecordView::FileType::RawS16, 16384, 3);
|
||||||
} else {
|
} else {
|
||||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||||
u"AUTO_AUDIO_", u"AUDIO",
|
u"AUTO_AUDIO", u"AUDIO",
|
||||||
RecordView::FileType::WAV, 4096, 4);
|
RecordView::FileType::WAV, 4096, 4);
|
||||||
|
record_view->set_filename_date_frequency(true);
|
||||||
}
|
}
|
||||||
|
record_view->set_auto_trim(false);
|
||||||
add_child(record_view.get());
|
add_child(record_view.get());
|
||||||
record_view->hidden(true);
|
record_view->hidden(true);
|
||||||
record_view->set_filename_date_frequency(true);
|
|
||||||
record_view->on_error = [this](std::string message) {
|
record_view->on_error = [this](std::string message) {
|
||||||
nav_.display_modal("Error", message);
|
nav_.display_modal("Error", message);
|
||||||
};
|
};
|
||||||
receiver_model.disable();
|
receiver_model.disable();
|
||||||
|
transmitter_model.disable();
|
||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
size_t recording_sampling_rate = 0;
|
size_t recording_sampling_rate = 0;
|
||||||
switch (new_mod) {
|
switch (new_mod) {
|
||||||
@@ -1144,7 +1216,6 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
|
|||||||
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
|
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
|
||||||
// record_view determines the correct oversampling to apply and returns the actual sample rate.
|
// record_view determines the correct oversampling to apply and returns the actual sample rate.
|
||||||
auto actual_sampling_rate = record_view->set_sampling_rate(sampling_rate);
|
auto actual_sampling_rate = record_view->set_sampling_rate(sampling_rate);
|
||||||
|
|
||||||
// The radio needs to know the effective sampling rate.
|
// The radio needs to know the effective sampling rate.
|
||||||
receiver_model.set_sampling_rate(actual_sampling_rate);
|
receiver_model.set_sampling_rate(actual_sampling_rate);
|
||||||
receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate));
|
receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate));
|
||||||
@@ -1222,4 +1293,132 @@ void ReconView::handle_remove_current_item() {
|
|||||||
update_description();
|
update_description();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReconView::on_repeat_tx_progress(const uint32_t progress) {
|
||||||
|
progressbar.set_value(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReconView::repeat_file_error(const std::filesystem::path& path, const std::string& message) {
|
||||||
|
nav_.display_modal("Error", "Error opening file \n" + path.string() + "\n" + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReconView::is_repeat_active() const {
|
||||||
|
return replay_thread != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReconView::start_repeat() {
|
||||||
|
// Prepare to send a file.
|
||||||
|
std::filesystem::path rawfile = u"/" + repeat_rec_path + u"/" + repeat_rec_file;
|
||||||
|
std::filesystem::path rawmeta = u"/" + repeat_rec_path + u"/" + repeat_rec_meta;
|
||||||
|
|
||||||
|
if (recon_tx == false) {
|
||||||
|
recon_tx = true;
|
||||||
|
|
||||||
|
if (record_view != nullptr) {
|
||||||
|
record_view->stop();
|
||||||
|
remove_child(record_view.get());
|
||||||
|
record_view.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
receiver_model.disable();
|
||||||
|
transmitter_model.disable();
|
||||||
|
baseband::shutdown();
|
||||||
|
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||||
|
|
||||||
|
size_t rawsize = 0;
|
||||||
|
{
|
||||||
|
File capture_file;
|
||||||
|
auto error = capture_file.open(rawfile);
|
||||||
|
if (error) {
|
||||||
|
repeat_file_error(rawfile, "Can't open file to send for size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rawsize = capture_file.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the transmit progress bar.
|
||||||
|
uint8_t sample_size = std::filesystem::capture_file_sample_size(rawfile);
|
||||||
|
progressbar.set_value(0);
|
||||||
|
progressbar.set_max(rawsize * sizeof(complex16_t) / sample_size);
|
||||||
|
progressbar.hidden(false);
|
||||||
|
|
||||||
|
auto metadata = read_metadata_file(rawmeta);
|
||||||
|
// If no metadata found, fallback to the TX frequency.
|
||||||
|
if (!metadata) {
|
||||||
|
metadata = {freq, 500'000};
|
||||||
|
repeat_file_error(rawmeta, "Can't open file to read meta, using default rx_freq,500'000");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the sample rate in proc_replay baseband.
|
||||||
|
baseband::set_sample_rate(metadata->sample_rate,
|
||||||
|
get_oversample_rate(metadata->sample_rate));
|
||||||
|
|
||||||
|
transmitter_model.set_sampling_rate(get_actual_sample_rate(metadata->sample_rate));
|
||||||
|
transmitter_model.set_baseband_bandwidth(metadata->sample_rate <= 500'000 ? 1'750'000 : 2'500'000); // TX LPF min 1M75 for SR <=500K, and 2M5 (by experimental test) for SR >500K
|
||||||
|
|
||||||
|
// set TX to repeater TX freq if entry is Repeater and have a valid freq, else use recorded one
|
||||||
|
if (current_entry().type == freqman_type::Repeater && current_entry().frequency_b != 0) {
|
||||||
|
transmitter_model.set_target_frequency(current_entry().frequency_b);
|
||||||
|
} else {
|
||||||
|
transmitter_model.set_target_frequency(metadata->center_frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set TX powers and enable transmitter
|
||||||
|
transmitter_model.set_tx_gain(persistent_memory::recon_repeat_gain());
|
||||||
|
transmitter_model.set_rf_amp(persistent_memory::recon_repeat_amp());
|
||||||
|
transmitter_model.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear replay thread and set reader
|
||||||
|
replay_thread.reset();
|
||||||
|
auto reader = std::make_unique<FileConvertReader>();
|
||||||
|
auto error = reader->open(rawfile);
|
||||||
|
if (error) {
|
||||||
|
repeat_file_error(rawfile, "Can't open file to send to thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repeat_ready_signal = true;
|
||||||
|
repeat_cur_rep++;
|
||||||
|
|
||||||
|
// ReplayThread starts immediately on construction; must be set before creating.
|
||||||
|
replay_thread = std::make_unique<ReplayThread>(
|
||||||
|
std::move(reader),
|
||||||
|
/* read_size */ repeat_read_size,
|
||||||
|
/* buffer_count */ repeat_buffer_count,
|
||||||
|
&repeat_ready_signal,
|
||||||
|
[](uint32_t return_code) {
|
||||||
|
ReplayThreadDoneMessage message{return_code};
|
||||||
|
EventDispatcher::send_message(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReconView::stop_repeat(const bool do_loop) {
|
||||||
|
repeat_ready_signal = false;
|
||||||
|
|
||||||
|
if (is_repeat_active()) {
|
||||||
|
replay_thread.reset();
|
||||||
|
transmitter_model.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat transmit if current number of repetitions (repeat_cur_rep) is < recon configured number of repetitions (recon_repeat_nb)
|
||||||
|
if (do_loop && repeat_cur_rep < persistent_memory::recon_repeat_nb()) {
|
||||||
|
start_repeat();
|
||||||
|
} else {
|
||||||
|
repeat_cur_rep = 0;
|
||||||
|
recon_tx = false;
|
||||||
|
reload_restart_recon();
|
||||||
|
progressbar.hidden(true);
|
||||||
|
set_dirty(); // fix progressbar no hiding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReconView::handle_repeat_thread_done(const uint32_t return_code) {
|
||||||
|
if (return_code == ReplayThread::END_OF_FILE) {
|
||||||
|
stop_repeat(true);
|
||||||
|
} else if (return_code == ReplayThread::READ_ERROR) {
|
||||||
|
stop_repeat(false);
|
||||||
|
repeat_file_error(u"/" + repeat_rec_path + u"/" + repeat_rec_file, "Can't open file to send.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@@ -41,10 +41,20 @@
|
|||||||
#include "app_settings.hpp"
|
#include "app_settings.hpp"
|
||||||
#include "radio_state.hpp"
|
#include "radio_state.hpp"
|
||||||
#include "ui_recon_settings.hpp"
|
#include "ui_recon_settings.hpp"
|
||||||
|
#include "ui_transmitter.hpp"
|
||||||
|
#include "replay_thread.hpp"
|
||||||
|
#include "metadata_file.hpp"
|
||||||
|
#include "ui_widget.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
#include "ui_freq_field.hpp"
|
||||||
|
#include "ui_spectrum.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
#define RECON_CFG_FILE "SETTINGS/recon.cfg"
|
#define RECON_CFG_FILE u"SETTINGS/recon.cfg"
|
||||||
|
|
||||||
enum class recon_mode : uint8_t {
|
enum class recon_mode : uint8_t {
|
||||||
Recon,
|
Recon,
|
||||||
@@ -66,10 +76,17 @@ class ReconView : public View {
|
|||||||
private:
|
private:
|
||||||
NavigationView& nav_;
|
NavigationView& nav_;
|
||||||
|
|
||||||
RxRadioState radio_state_{};
|
RxRadioState rx_radio_state_{};
|
||||||
|
TxRadioState tx_radio_state_{
|
||||||
|
0 /* frequency */,
|
||||||
|
1750000 /* bandwidth */,
|
||||||
|
500000 /* sampling rate */
|
||||||
|
};
|
||||||
app_settings::SettingsManager settings_{
|
app_settings::SettingsManager settings_{
|
||||||
"rx_recon"sv, app_settings::Mode::RX};
|
"rx_tx_recon"sv, app_settings::Mode::RX_TX};
|
||||||
|
;
|
||||||
|
|
||||||
|
void reload_restart_recon();
|
||||||
void check_update_ranges_from_current();
|
void check_update_ranges_from_current();
|
||||||
void set_loop_config(bool v);
|
void set_loop_config(bool v);
|
||||||
void clear_freqlist_for_ui_action();
|
void clear_freqlist_for_ui_action();
|
||||||
@@ -125,6 +142,7 @@ class ReconView : public View {
|
|||||||
bool load_freqs{true};
|
bool load_freqs{true};
|
||||||
bool load_ranges{true};
|
bool load_ranges{true};
|
||||||
bool load_hamradios{true};
|
bool load_hamradios{true};
|
||||||
|
bool load_repeaters{true};
|
||||||
bool update_ranges{true};
|
bool update_ranges{true};
|
||||||
bool fwd{true};
|
bool fwd{true};
|
||||||
bool recon{true};
|
bool recon{true};
|
||||||
@@ -163,6 +181,25 @@ class ReconView : public View {
|
|||||||
systime_t chrono_start{};
|
systime_t chrono_start{};
|
||||||
systime_t chrono_end{};
|
systime_t chrono_end{};
|
||||||
|
|
||||||
|
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;
|
||||||
|
int64_t repeat_sample_rate = 0;
|
||||||
|
static constexpr uint32_t repeat_bandwidth = 2500000;
|
||||||
|
void on_repeat_tx_progress(const uint32_t progress);
|
||||||
|
void start_repeat();
|
||||||
|
void stop_repeat(const bool do_loop);
|
||||||
|
bool is_repeat_active() const;
|
||||||
|
void handle_repeat_thread_done(const uint32_t return_code);
|
||||||
|
void repeat_file_error(const std::filesystem::path& path, const std::string& message);
|
||||||
|
std::filesystem::path repeat_file_path{};
|
||||||
|
std::unique_ptr<ReplayThread> replay_thread{};
|
||||||
|
bool repeat_ready_signal{false};
|
||||||
|
bool recon_tx{false};
|
||||||
|
|
||||||
// Persisted settings.
|
// Persisted settings.
|
||||||
SettingsStore ui_settings{
|
SettingsStore ui_settings{
|
||||||
"recon"sv,
|
"recon"sv,
|
||||||
@@ -354,17 +391,47 @@ class ReconView : public View {
|
|||||||
{168, (35 * 8) - 4, 72, 28},
|
{168, (35 * 8) - 4, 72, 28},
|
||||||
"<REMOVE>"};
|
"<REMOVE>"};
|
||||||
|
|
||||||
|
ProgressBar progressbar{
|
||||||
|
{0 * 8, SCREEN_H / 2 - 16, SCREEN_W, 32}};
|
||||||
|
|
||||||
|
TransmitterView2 tx_view{
|
||||||
|
{11 * 8, 2 * 16},
|
||||||
|
/*short_ui*/ true};
|
||||||
|
|
||||||
MessageHandlerRegistration message_handler_coded_squelch{
|
MessageHandlerRegistration message_handler_coded_squelch{
|
||||||
Message::ID::CodedSquelch,
|
Message::ID::CodedSquelch,
|
||||||
[this](const Message* const p) {
|
[this](const Message* const p) {
|
||||||
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
|
const auto message = *reinterpret_cast<const CodedSquelchMessage*>(p);
|
||||||
this->handle_coded_squelch(message.value);
|
handle_coded_squelch(message.value);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
MessageHandlerRegistration message_handler_stats{
|
MessageHandlerRegistration message_handler_stats{
|
||||||
Message::ID::ChannelStatistics,
|
Message::ID::ChannelStatistics,
|
||||||
[this](const Message* const p) {
|
[this](const Message* const p) {
|
||||||
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
|
on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
|
||||||
|
}};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_replay_thread_error{
|
||||||
|
Message::ID::ReplayThreadDone,
|
||||||
|
[this](const Message* p) {
|
||||||
|
auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||||
|
handle_repeat_thread_done(message.return_code);
|
||||||
|
}};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_fifo_signal{
|
||||||
|
Message::ID::RequestSignal,
|
||||||
|
[this](const Message* p) {
|
||||||
|
auto message = static_cast<const RequestSignalMessage*>(p);
|
||||||
|
if (message->signal == RequestSignalMessage::Signal::FillRequest) {
|
||||||
|
repeat_ready_signal = true;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
MessageHandlerRegistration message_handler_tx_progress{
|
||||||
|
Message::ID::TXProgress,
|
||||||
|
[this](const Message* p) {
|
||||||
|
auto message = *reinterpret_cast<const TXProgressMessage*>(p);
|
||||||
|
on_repeat_tx_progress(message.progress);
|
||||||
}};
|
}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -99,8 +99,13 @@ void ReconSetupViewMore::save() {
|
|||||||
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
|
persistent_memory::set_recon_load_freqs(checkbox_load_freqs.value());
|
||||||
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
|
persistent_memory::set_recon_load_ranges(checkbox_load_ranges.value());
|
||||||
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
|
persistent_memory::set_recon_load_hamradios(checkbox_load_hamradios.value());
|
||||||
|
persistent_memory::set_recon_load_repeaters(checkbox_load_repeaters.value());
|
||||||
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
|
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
|
||||||
persistent_memory::set_recon_auto_record_locked(checkbox_auto_record_locked.value());
|
persistent_memory::set_recon_auto_record_locked(checkbox_auto_record_locked.value());
|
||||||
|
persistent_memory::set_recon_repeat_recorded(checkbox_repeat_recorded.value());
|
||||||
|
persistent_memory::set_recon_repeat_nb(field_repeat_nb.value());
|
||||||
|
persistent_memory::set_recon_repeat_amp(checkbox_repeat_amp.value());
|
||||||
|
persistent_memory::set_recon_repeat_gain(field_repeat_gain.value());
|
||||||
};
|
};
|
||||||
|
|
||||||
void ReconSetupViewMain::focus() {
|
void ReconSetupViewMain::focus() {
|
||||||
@@ -113,16 +118,50 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
|
|||||||
hidden(true);
|
hidden(true);
|
||||||
|
|
||||||
add_children({&checkbox_load_freqs,
|
add_children({&checkbox_load_freqs,
|
||||||
|
&checkbox_load_repeaters,
|
||||||
&checkbox_load_ranges,
|
&checkbox_load_ranges,
|
||||||
&checkbox_load_hamradios,
|
&checkbox_load_hamradios,
|
||||||
&checkbox_update_ranges_when_recon,
|
&checkbox_update_ranges_when_recon,
|
||||||
&checkbox_auto_record_locked});
|
&checkbox_auto_record_locked,
|
||||||
|
&checkbox_repeat_recorded,
|
||||||
|
&text_repeat_nb,
|
||||||
|
&field_repeat_nb,
|
||||||
|
&checkbox_repeat_amp,
|
||||||
|
&text_repeat_gain,
|
||||||
|
&field_repeat_gain});
|
||||||
|
|
||||||
|
// tx options have to be in yellow to inform the users that activating them will make the device transmit
|
||||||
|
checkbox_repeat_recorded.set_style(&Styles::yellow);
|
||||||
|
text_repeat_nb.set_style(&Styles::yellow);
|
||||||
|
field_repeat_nb.set_style(&Styles::yellow);
|
||||||
|
checkbox_repeat_amp.set_style(&Styles::yellow);
|
||||||
|
text_repeat_gain.set_style(&Styles::yellow);
|
||||||
|
field_repeat_gain.set_style(&Styles::yellow);
|
||||||
|
|
||||||
checkbox_load_freqs.set_value(persistent_memory::recon_load_freqs());
|
checkbox_load_freqs.set_value(persistent_memory::recon_load_freqs());
|
||||||
|
checkbox_load_repeaters.set_value(persistent_memory::recon_load_repeaters());
|
||||||
checkbox_load_ranges.set_value(persistent_memory::recon_load_ranges());
|
checkbox_load_ranges.set_value(persistent_memory::recon_load_ranges());
|
||||||
checkbox_load_hamradios.set_value(persistent_memory::recon_load_hamradios());
|
checkbox_load_hamradios.set_value(persistent_memory::recon_load_hamradios());
|
||||||
checkbox_update_ranges_when_recon.set_value(persistent_memory::recon_update_ranges_when_recon());
|
checkbox_update_ranges_when_recon.set_value(persistent_memory::recon_update_ranges_when_recon());
|
||||||
checkbox_auto_record_locked.set_value(persistent_memory::recon_auto_record_locked());
|
checkbox_auto_record_locked.set_value(persistent_memory::recon_auto_record_locked());
|
||||||
|
checkbox_repeat_recorded.set_value(persistent_memory::recon_repeat_recorded());
|
||||||
|
checkbox_repeat_amp.set_value(persistent_memory::recon_repeat_amp());
|
||||||
|
field_repeat_nb.set_value(persistent_memory::recon_repeat_nb());
|
||||||
|
field_repeat_gain.set_value(persistent_memory::recon_repeat_gain());
|
||||||
|
|
||||||
|
// tx warning modal
|
||||||
|
checkbox_repeat_recorded.on_select = [this, &nav](Checkbox&, bool v) {
|
||||||
|
if (v) {
|
||||||
|
nav.display_modal(
|
||||||
|
"TX WARNING",
|
||||||
|
"This activate TX ability\nin Recon !",
|
||||||
|
YESNO,
|
||||||
|
[this, &nav](bool choice) {
|
||||||
|
if (!choice)
|
||||||
|
checkbox_repeat_recorded.set_value(choice);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
void ReconSetupViewMore::focus() {
|
void ReconSetupViewMore::focus() {
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "ui_tabview.hpp"
|
#include "ui_tabview.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
|
#include "ui_styles.hpp"
|
||||||
|
|
||||||
// 1Mhz helper
|
// 1Mhz helper
|
||||||
#ifdef OneMHz
|
#ifdef OneMHz
|
||||||
@@ -116,26 +117,70 @@ class ReconSetupViewMore : public View {
|
|||||||
Checkbox checkbox_load_freqs{
|
Checkbox checkbox_load_freqs{
|
||||||
{1 * 8, 12},
|
{1 * 8, 12},
|
||||||
3,
|
3,
|
||||||
"input: load freqs"};
|
"load freq",
|
||||||
|
true};
|
||||||
|
|
||||||
|
Checkbox checkbox_load_repeaters{
|
||||||
|
{14 * 8, 12},
|
||||||
|
3,
|
||||||
|
"load repeater",
|
||||||
|
true};
|
||||||
|
|
||||||
Checkbox checkbox_load_ranges{
|
Checkbox checkbox_load_ranges{
|
||||||
{1 * 8, 42},
|
{1 * 8, 42},
|
||||||
3,
|
3,
|
||||||
"input: load ranges"};
|
"load range",
|
||||||
|
true};
|
||||||
|
|
||||||
Checkbox checkbox_load_hamradios{
|
Checkbox checkbox_load_hamradios{
|
||||||
{1 * 8, 72},
|
{1 * 8, 72},
|
||||||
3,
|
3,
|
||||||
"input: load hamradios"};
|
"load hamradio",
|
||||||
|
true};
|
||||||
|
|
||||||
Checkbox checkbox_update_ranges_when_recon{
|
Checkbox checkbox_update_ranges_when_recon{
|
||||||
{1 * 8, 102},
|
{1 * 8, 102},
|
||||||
3,
|
3,
|
||||||
"auto update m-ranges"};
|
"auto update m-ranges"};
|
||||||
|
|
||||||
Checkbox checkbox_auto_record_locked{
|
Checkbox checkbox_auto_record_locked{
|
||||||
{1 * 8, 132},
|
{1 * 8, 132},
|
||||||
3,
|
3,
|
||||||
"record locked periods"};
|
"record locked periods"};
|
||||||
|
|
||||||
|
Checkbox checkbox_repeat_recorded{
|
||||||
|
{1 * 8, 162},
|
||||||
|
3,
|
||||||
|
"repeater,"};
|
||||||
|
|
||||||
|
Text text_repeat_nb{
|
||||||
|
{14 * 8, 165, 3 * 8, 22},
|
||||||
|
"nb:"};
|
||||||
|
|
||||||
|
NumberField field_repeat_nb{
|
||||||
|
{18 * 8, 165},
|
||||||
|
2,
|
||||||
|
{1, 99},
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
};
|
||||||
|
|
||||||
|
Checkbox checkbox_repeat_amp{
|
||||||
|
{1 * 8, 192},
|
||||||
|
3,
|
||||||
|
"AMP,"};
|
||||||
|
|
||||||
|
Text text_repeat_gain{
|
||||||
|
{10 * 8, 196, 5 * 8, 22},
|
||||||
|
"GAIN:"};
|
||||||
|
|
||||||
|
NumberField field_repeat_gain{
|
||||||
|
{16 * 8, 196},
|
||||||
|
2,
|
||||||
|
{0, 47},
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReconSetupView : public View {
|
class ReconSetupView : public View {
|
||||||
|
@@ -564,6 +564,7 @@ void ScannerView::frequency_file_load(const fs::path& path) {
|
|||||||
def_step_index = entry.step;
|
def_step_index = entry.step;
|
||||||
|
|
||||||
switch (entry.type) {
|
switch (entry.type) {
|
||||||
|
case freqman_type::Repeater:
|
||||||
case freqman_type::Single:
|
case freqman_type::Single:
|
||||||
entries.push_back({entry.frequency_a, entry.description});
|
entries.push_back({entry.frequency_a, entry.description});
|
||||||
break;
|
break;
|
||||||
|
@@ -133,7 +133,6 @@ SetRadioView::SetRadioView(
|
|||||||
&check_clkout,
|
&check_clkout,
|
||||||
&field_clkout_freq,
|
&field_clkout_freq,
|
||||||
&labels_clkout_khz,
|
&labels_clkout_khz,
|
||||||
&value_freq_step,
|
|
||||||
&labels_bias,
|
&labels_bias,
|
||||||
&check_bias,
|
&check_bias,
|
||||||
&disable_external_tcxo, // TODO: always show?
|
&disable_external_tcxo, // TODO: always show?
|
||||||
@@ -185,29 +184,20 @@ SetRadioView::SetRadioView(
|
|||||||
send_system_refresh();
|
send_system_refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
field_clkout_freq.set_value(pmem::clkout_freq());
|
// Disallow CLKOUT freq change on hackrf_r9 due to dependencies on GP_CLKIN (same Si5351A clock);
|
||||||
value_freq_step.set_style(&Styles::light_grey);
|
// see comments in ClockManager::enable_clock_output()
|
||||||
|
if (hackrf_r9) {
|
||||||
|
if (pmem::clkout_freq() != 10000)
|
||||||
|
pmem::set_clkout_freq(10000);
|
||||||
|
field_clkout_freq.set_focusable(false);
|
||||||
|
}
|
||||||
|
|
||||||
field_clkout_freq.on_select = [this](NumberField&) {
|
field_clkout_freq.set_value(pmem::clkout_freq());
|
||||||
freq_step_khz++;
|
field_clkout_freq.on_change = [this](SymField&) {
|
||||||
if (freq_step_khz > 3) {
|
if (field_clkout_freq.to_integer() < 4) // Min. CLK out of Si5351A/B/C-B is 2.5khz , but in our application -intermediate freq 800Mhz-,Min working CLK=4khz.
|
||||||
freq_step_khz = 0;
|
field_clkout_freq.set_value(4);
|
||||||
}
|
if (field_clkout_freq.to_integer() > 60000)
|
||||||
switch (freq_step_khz) {
|
field_clkout_freq.set_value(60000);
|
||||||
case 0:
|
|
||||||
value_freq_step.set(" |");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
value_freq_step.set(" | ");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
value_freq_step.set(" | ");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
value_freq_step.set("| ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
field_clkout_freq.set_step(pow(10, freq_step_khz));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
check_bias.set_value(get_antenna_bias());
|
check_bias.set_value(get_antenna_bias());
|
||||||
@@ -248,7 +238,7 @@ void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) {
|
|||||||
SetFrequencyCorrectionModel SetRadioView::form_collect() {
|
SetFrequencyCorrectionModel SetRadioView::form_collect() {
|
||||||
return {
|
return {
|
||||||
.ppm = static_cast<int8_t>(field_ppm.value()),
|
.ppm = static_cast<int8_t>(field_ppm.value()),
|
||||||
.freq = static_cast<uint32_t>(field_clkout_freq.value()),
|
.freq = static_cast<uint32_t>(field_clkout_freq.to_integer()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -163,20 +163,14 @@ class SetRadioView : public View {
|
|||||||
13,
|
13,
|
||||||
"Enable CLKOUT"};
|
"Enable CLKOUT"};
|
||||||
|
|
||||||
NumberField field_clkout_freq{
|
SymField field_clkout_freq{
|
||||||
{20 * 8, 6 * 16},
|
{20 * 8, 6 * 16},
|
||||||
5,
|
5,
|
||||||
{10, 60000},
|
SymField::Type::Dec};
|
||||||
1000,
|
|
||||||
' '};
|
|
||||||
|
|
||||||
Labels labels_clkout_khz{
|
Labels labels_clkout_khz{
|
||||||
{{26 * 8, 6 * 16}, "kHz", Color::light_grey()}};
|
{{26 * 8, 6 * 16}, "kHz", Color::light_grey()}};
|
||||||
|
|
||||||
Text value_freq_step{
|
|
||||||
{21 * 8, (7 * 16), 4 * 8, 16},
|
|
||||||
"| "};
|
|
||||||
|
|
||||||
Labels labels_bias{
|
Labels labels_bias{
|
||||||
{{4 * 8 + 4, 8 * 16}, "CAUTION: Ensure that all", Color::red()},
|
{{4 * 8 + 4, 8 * 16}, "CAUTION: Ensure that all", Color::red()},
|
||||||
{{5 * 8 + 0, 9 * 16}, "devices attached to the", Color::red()},
|
{{5 * 8 + 0, 9 * 16}, "devices attached to the", Color::red()},
|
||||||
|
@@ -561,26 +561,32 @@ void ClockManager::stop_audio_pll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClockManager::enable_clock_output(bool enable) {
|
void ClockManager::enable_clock_output(bool enable) {
|
||||||
|
if (hackrf_r9) {
|
||||||
|
gpio_r9_clkout_en.output();
|
||||||
|
gpio_r9_clkout_en.write(enable);
|
||||||
|
|
||||||
|
// NOTE: RETURNING HERE IF HACKRF_R9 TO PREVENT CLK2 FROM BEING DISABLED OR FREQ MODIFIED SINCE CLK2 ON R9 IS
|
||||||
|
// USED FOR BOTH CLKOUT AND FOR THE MCU_CLOCK (== GP_CLKIN) WHICH OTHER LP43XX CLOCKS CURRENTLY RELY ON.
|
||||||
|
// FUTURE TBD: REMOVE OTHER LP43XX CLOCK DEPENDENCIES ON GP_CLKIN, THEN DELETE THE return LINE BELOW TO ALLOW
|
||||||
|
// CLKOUT FREQ CHANGES ON R9 BOARDS.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clkout_select = hackrf_r9 ? clock_generator_output_r9_clkout : clock_generator_output_og_clkout;
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
clock_generator.enable_output(clock_generator_output_og_clkout);
|
clock_generator.enable_output(clkout_select);
|
||||||
if (portapack::persistent_memory::clkout_freq() < 1000) {
|
if (portapack::persistent_memory::clkout_freq() < 1000) {
|
||||||
clock_generator.set_ms_frequency(clock_generator_output_og_clkout, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7);
|
clock_generator.set_ms_frequency(clkout_select, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7);
|
||||||
} else {
|
} else {
|
||||||
clock_generator.set_ms_frequency(clock_generator_output_og_clkout, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0);
|
clock_generator.set_ms_frequency(clkout_select, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clock_generator.disable_output(clock_generator_output_og_clkout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto si5351_clock_control_common = hackrf_r9
|
auto si5351_clock_control_common = hackrf_r9 ? si5351a_clock_control_common : si5351c_clock_control_common;
|
||||||
? si5351a_clock_control_common
|
const auto ref_pll = hackrf_r9 ? ClockControl::MultiSynthSource::PLLA : get_si5351c_reference_clock_generator_pll(reference.source);
|
||||||
: si5351c_clock_control_common;
|
clock_generator.set_clock_control(clkout_select, si5351_clock_control_common[clkout_select].ms_src(ref_pll).clk_pdn(ClockControl::ClockPowerDown::Power_On));
|
||||||
const auto ref_pll = hackrf_r9
|
} else {
|
||||||
? ClockControl::MultiSynthSource::PLLA
|
clock_generator.disable_output(clkout_select);
|
||||||
: get_si5351c_reference_clock_generator_pll(reference.source);
|
clock_generator.set_clock_control(clkout_select, ClockControl::power_off());
|
||||||
|
}
|
||||||
if (enable)
|
|
||||||
clock_generator.set_clock_control(clock_generator_output_og_clkout, si5351_clock_control_common[clock_generator_output_og_clkout].ms_src(ref_pll).clk_pdn(ClockControl::ClockPowerDown::Power_On));
|
|
||||||
else
|
|
||||||
clock_generator.set_clock_control(clock_generator_output_og_clkout, ClockControl::power_off());
|
|
||||||
}
|
}
|
||||||
|
1058
firmware/application/external/blespam/ui_blespam.cpp
vendored
1058
firmware/application/external/blespam/ui_blespam.cpp
vendored
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,8 @@
|
|||||||
#ifndef __UI_BLESPAM_H__
|
#ifndef __UI_BLESPAM_H__
|
||||||
#define __UI_BLESPAM_H__
|
#define __UI_BLESPAM_H__
|
||||||
|
|
||||||
|
#define BLESPMUSECONSOLE 1
|
||||||
|
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include "ui_language.hpp"
|
#include "ui_language.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
@@ -111,9 +113,10 @@ class BLESpamView : public View {
|
|||||||
LanguageHelper::currentMessages[LANG_START]};
|
LanguageHelper::currentMessages[LANG_START]};
|
||||||
Checkbox chk_randdev{{100, 16}, 10, "Rnd device", true};
|
Checkbox chk_randdev{{100, 16}, 10, "Rnd device", true};
|
||||||
|
|
||||||
|
#ifdef BLESPMUSECONSOLE
|
||||||
Console console{
|
Console console{
|
||||||
{0, 70, 240, 220}};
|
{0, 70, 240, 220}};
|
||||||
|
#endif
|
||||||
OptionsField options_atkmode{
|
OptionsField options_atkmode{
|
||||||
{0 * 8, 2 * 8},
|
{0 * 8, 2 * 8},
|
||||||
10,
|
10,
|
||||||
@@ -134,7 +137,7 @@ class BLESpamView : public View {
|
|||||||
bool randomDev{true};
|
bool randomDev{true};
|
||||||
|
|
||||||
uint8_t channel_number = 37;
|
uint8_t channel_number = 37;
|
||||||
char mac[13] = "010203040507";
|
char mac[13] = "010203040407";
|
||||||
char advertisementData[63] = {"03032CFE06162CFED5A59E020AB4\0"};
|
char advertisementData[63] = {"03032CFE06162CFED5A59E020AB4\0"};
|
||||||
PKT_TYPE pduType = {PKT_TYPE_DISCOVERY};
|
PKT_TYPE pduType = {PKT_TYPE_DISCOVERY};
|
||||||
|
|
||||||
@@ -161,6 +164,8 @@ class BLESpamView : public View {
|
|||||||
this->on_tx_progress(message.done);
|
this->on_tx_progress(message.done);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
uint8_t packet[80];
|
||||||
|
|
||||||
// continuity
|
// continuity
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -227,7 +232,7 @@ class BLESpamView : public View {
|
|||||||
static const uint16_t fastpairModels_count;
|
static const uint16_t fastpairModels_count;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
const char* name; // could be moved too
|
// const char* name; // could be moved too
|
||||||
} fpUi32;
|
} fpUi32;
|
||||||
static const fpUi32 fastpairModels[];
|
static const fpUi32 fastpairModels[];
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
|
#include "ui_language.hpp"
|
||||||
#include "ui_widget.hpp"
|
#include "ui_widget.hpp"
|
||||||
#include "ui_styles.hpp"
|
#include "ui_styles.hpp"
|
||||||
#include "ui_navigation.hpp"
|
#include "ui_navigation.hpp"
|
||||||
@@ -56,8 +57,8 @@ class RangeView : public View {
|
|||||||
const Style& style_info = Styles::grey;
|
const Style& style_info = Styles::grey;
|
||||||
|
|
||||||
Labels labels{
|
Labels labels{
|
||||||
{{2 * 8, 8 * 8 + 4}, "Start", Color::light_grey()},
|
{{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Color::light_grey()},
|
||||||
{{23 * 8, 8 * 8 + 4}, "Stop", Color::light_grey()},
|
{{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Color::light_grey()},
|
||||||
{{12 * 8, 5 * 8 - 4}, "Center", Color::light_grey()},
|
{{12 * 8, 5 * 8 - 4}, "Center", Color::light_grey()},
|
||||||
{{12 * 8 + 4, 13 * 8}, "Width", Color::light_grey()}};
|
{{12 * 8 + 4, 13 * 8}, "Width", Color::light_grey()}};
|
||||||
|
|
||||||
@@ -226,7 +227,7 @@ class JammerView : public View {
|
|||||||
|
|
||||||
Button button_transmit{
|
Button button_transmit{
|
||||||
{148, 216, 80, 80},
|
{148, 216, 80, 80},
|
||||||
"START"};
|
LanguageHelper::currentMessages[LANG_START]};
|
||||||
|
|
||||||
MessageHandlerRegistration message_handler_retune{
|
MessageHandlerRegistration message_handler_retune{
|
||||||
Message::ID::Retune,
|
Message::ID::Retune,
|
||||||
|
@@ -185,6 +185,8 @@ bool operator==(const freqman_entry& lhs, const freqman_entry& rhs) {
|
|||||||
} else if (lhs.type == freqman_type::HamRadio) {
|
} else if (lhs.type == freqman_type::HamRadio) {
|
||||||
equal = lhs.frequency_b == rhs.frequency_b &&
|
equal = lhs.frequency_b == rhs.frequency_b &&
|
||||||
lhs.tone == rhs.tone;
|
lhs.tone == rhs.tone;
|
||||||
|
} else if (lhs.type == freqman_type::Repeater) {
|
||||||
|
equal = lhs.frequency_b == rhs.frequency_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
return equal;
|
return equal;
|
||||||
@@ -248,6 +250,10 @@ std::string pretty_string(const freqman_entry& entry, size_t max_length) {
|
|||||||
str = "R:" + to_string_rounded_freq(entry.frequency_a, 1) + "M,T:" +
|
str = "R:" + to_string_rounded_freq(entry.frequency_a, 1) + "M,T:" +
|
||||||
to_string_rounded_freq(entry.frequency_b, 1) + "M: " + entry.description;
|
to_string_rounded_freq(entry.frequency_b, 1) + "M: " + entry.description;
|
||||||
break;
|
break;
|
||||||
|
case freqman_type::Repeater:
|
||||||
|
str = "L:" + to_string_rounded_freq(entry.frequency_a, 1) + "M,T:" +
|
||||||
|
to_string_rounded_freq(entry.frequency_b, 1) + "M: " + entry.description;
|
||||||
|
break;
|
||||||
case freqman_type::Raw:
|
case freqman_type::Raw:
|
||||||
str = entry.description;
|
str = entry.description;
|
||||||
break;
|
break;
|
||||||
@@ -292,6 +298,10 @@ std::string to_freqman_string(const freqman_entry& entry) {
|
|||||||
if (is_valid(entry.tone))
|
if (is_valid(entry.tone))
|
||||||
append_field("c", tonekey::tone_key_value_string(entry.tone));
|
append_field("c", tonekey::tone_key_value_string(entry.tone));
|
||||||
break;
|
break;
|
||||||
|
case freqman_type::Repeater:
|
||||||
|
append_field("l", to_string_dec_uint(entry.frequency_a));
|
||||||
|
append_field("t", to_string_dec_uint(entry.frequency_b));
|
||||||
|
break;
|
||||||
case freqman_type::Raw:
|
case freqman_type::Raw:
|
||||||
return entry.description;
|
return entry.description;
|
||||||
default:
|
default:
|
||||||
@@ -372,16 +382,18 @@ bool parse_freqman_entry(std::string_view str, freqman_entry& entry) {
|
|||||||
parse_int(value, entry.frequency_a);
|
parse_int(value, entry.frequency_a);
|
||||||
} else if (key == "m") {
|
} else if (key == "m") {
|
||||||
entry.modulation = find_by_name(freqman_modulations, value);
|
entry.modulation = find_by_name(freqman_modulations, value);
|
||||||
} else if (key == "r") {
|
} else if (key == "r") { // HamRadio relay receive freq
|
||||||
entry.type = freqman_type::HamRadio;
|
entry.type = freqman_type::HamRadio;
|
||||||
parse_int(value, entry.frequency_a);
|
parse_int(value, entry.frequency_a);
|
||||||
|
} else if (key == "l") { // Portapack Repeater mode listen freq. Used as a single freq if Repeater mode isn't active
|
||||||
|
entry.type = freqman_type::Repeater;
|
||||||
|
parse_int(value, entry.frequency_a);
|
||||||
} else if (key == "s") {
|
} else if (key == "s") {
|
||||||
entry.step = find_by_name(freqman_steps_short, value);
|
entry.step = find_by_name(freqman_steps_short, value);
|
||||||
} else if (key == "t") {
|
} else if (key == "t") { // Tx freq: scanned as a single freq in HamRadio mode, used as TX freq in Repeater mode and ignored by the scanner
|
||||||
parse_int(value, entry.frequency_b);
|
parse_int(value, entry.frequency_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return is_valid(entry);
|
return is_valid(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +412,8 @@ bool parse_freqman_file(const fs::path& path, freqman_db& db, freqman_load_optio
|
|||||||
if (entry.type == freqman_type::Unknown ||
|
if (entry.type == freqman_type::Unknown ||
|
||||||
(entry.type == freqman_type::Single && !options.load_freqs) ||
|
(entry.type == freqman_type::Single && !options.load_freqs) ||
|
||||||
(entry.type == freqman_type::Range && !options.load_ranges) ||
|
(entry.type == freqman_type::Range && !options.load_ranges) ||
|
||||||
(entry.type == freqman_type::HamRadio && !options.load_hamradios)) {
|
(entry.type == freqman_type::HamRadio && !options.load_hamradios) ||
|
||||||
|
(entry.type == freqman_type::Repeater && !options.load_repeaters)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,8 +446,8 @@ bool is_valid(const freqman_entry& entry) {
|
|||||||
if (entry.frequency_a == 0)
|
if (entry.frequency_a == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Frequency B must be set for type Range or Ham Radio
|
// Frequency B must be set for type Range or HamRadio or Repeater
|
||||||
if (entry.type == freqman_type::Range || entry.type == freqman_type::HamRadio) {
|
if (entry.type == freqman_type::Range || entry.type == freqman_type::HamRadio || entry.type == freqman_type::Repeater) {
|
||||||
if (entry.frequency_b == 0)
|
if (entry.frequency_b == 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,7 @@ enum class freqman_type : uint8_t {
|
|||||||
Single, // f=
|
Single, // f=
|
||||||
Range, // a=,b=
|
Range, // a=,b=
|
||||||
HamRadio, // r=,t=
|
HamRadio, // r=,t=
|
||||||
|
Repeater, // l=,t=
|
||||||
Raw, // line content in description
|
Raw, // line content in description
|
||||||
Unknown,
|
Unknown,
|
||||||
};
|
};
|
||||||
@@ -167,6 +168,7 @@ struct freqman_load_options {
|
|||||||
bool load_freqs{true};
|
bool load_freqs{true};
|
||||||
bool load_ranges{true};
|
bool load_ranges{true};
|
||||||
bool load_hamradios{true};
|
bool load_hamradios{true};
|
||||||
|
bool load_repeaters{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
using freqman_entry_ptr = std::unique_ptr<freqman_entry>;
|
using freqman_entry_ptr = std::unique_ptr<freqman_entry>;
|
||||||
|
@@ -173,6 +173,9 @@ SystemStatusView::SystemStatusView(
|
|||||||
pmem::load_persistent_settings_from_file();
|
pmem::load_persistent_settings_from_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configure CLKOUT per pmem setting
|
||||||
|
portapack::clock_manager.enable_clock_output(pmem::clkout_enabled());
|
||||||
|
|
||||||
// force apply of selected sdcard speed override at UI startup
|
// force apply of selected sdcard speed override at UI startup
|
||||||
pmem::set_config_sdcard_high_speed_io(pmem::config_sdcard_high_speed_io(), false);
|
pmem::set_config_sdcard_high_speed_io(pmem::config_sdcard_high_speed_io(), false);
|
||||||
|
|
||||||
|
@@ -145,6 +145,15 @@ OversampleRate RecordView::get_oversample_rate(uint32_t sample_rate) {
|
|||||||
// Setter for datetime and frequency filename
|
// Setter for datetime and frequency filename
|
||||||
void RecordView::set_filename_date_frequency(bool set) {
|
void RecordView::set_filename_date_frequency(bool set) {
|
||||||
filename_date_frequency = set;
|
filename_date_frequency = set;
|
||||||
|
if (set)
|
||||||
|
filename_as_is = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter for leaving the filename untouched
|
||||||
|
void RecordView::set_filename_as_is(bool set) {
|
||||||
|
filename_as_is = set;
|
||||||
|
if (set)
|
||||||
|
filename_date_frequency = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordView::is_active() const {
|
bool RecordView::is_active() const {
|
||||||
@@ -186,9 +195,11 @@ void RecordView::start() {
|
|||||||
base_path = filename_stem_pattern.string() + "_" + date_time + "_" +
|
base_path = filename_stem_pattern.string() + "_" + date_time + "_" +
|
||||||
trim(to_string_freq(receiver_model.target_frequency())) + "Hz";
|
trim(to_string_freq(receiver_model.target_frequency())) + "Hz";
|
||||||
base_path = folder / base_path;
|
base_path = folder / base_path;
|
||||||
} else {
|
} else if (filename_as_is) {
|
||||||
|
base_path = filename_stem_pattern.string();
|
||||||
|
base_path = folder / base_path;
|
||||||
|
} else
|
||||||
base_path = next_filename_matching_pattern(folder / filename_stem_pattern);
|
base_path = next_filename_matching_pattern(folder / filename_stem_pattern);
|
||||||
}
|
|
||||||
|
|
||||||
if (base_path.empty()) {
|
if (base_path.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@@ -73,6 +73,7 @@ class RecordView : public View {
|
|||||||
bool is_active() const;
|
bool is_active() const;
|
||||||
|
|
||||||
void set_filename_date_frequency(bool set);
|
void set_filename_date_frequency(bool set);
|
||||||
|
void set_filename_as_is(bool set);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void toggle();
|
void toggle();
|
||||||
@@ -91,6 +92,7 @@ class RecordView : public View {
|
|||||||
|
|
||||||
// Time Stamp
|
// Time Stamp
|
||||||
bool filename_date_frequency = false;
|
bool filename_date_frequency = false;
|
||||||
|
bool filename_as_is = false;
|
||||||
rtc::RTC datetime{};
|
rtc::RTC datetime{};
|
||||||
|
|
||||||
const std::filesystem::path filename_stem_pattern;
|
const std::filesystem::path filename_stem_pattern;
|
||||||
|
@@ -418,21 +418,18 @@ static void cmd_sd_read(BaseSequentialStream* chp, int argc, char* argv[]) {
|
|||||||
|
|
||||||
int size = (int)strtol(argv[0], NULL, 10);
|
int size = (int)strtol(argv[0], NULL, 10);
|
||||||
|
|
||||||
uint8_t buffer[16];
|
uint8_t buffer[62];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
File::Size bytes_to_read = size > 16 ? 16 : size;
|
File::Size bytes_to_read = size > 62 ? 62 : size;
|
||||||
auto bytes_read = shell_file->read(buffer, bytes_to_read);
|
auto bytes_read = shell_file->read(buffer, bytes_to_read);
|
||||||
if (bytes_read.is_error()) {
|
if (bytes_read.is_error()) {
|
||||||
chprintf(chp, "error %d\r\n", bytes_read.error());
|
chprintf(chp, "error %d\r\n", bytes_read.error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
std::string res = to_string_hex_array(buffer, bytes_read.value());
|
||||||
for (size_t i = 0; i < bytes_read.value(); i++)
|
res += "\r\n";
|
||||||
chprintf(chp, "%02X", buffer[i]);
|
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)res.c_str(), res.size());
|
||||||
|
|
||||||
chprintf(chp, "\r\n");
|
|
||||||
|
|
||||||
if (bytes_to_read != bytes_read.value())
|
if (bytes_to_read != bytes_read.value())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -68,6 +68,7 @@ constexpr size_t clock_generator_output_og_mcu_clkin = 7;
|
|||||||
|
|
||||||
constexpr size_t clock_generator_output_r9_if = 0;
|
constexpr size_t clock_generator_output_r9_if = 0;
|
||||||
constexpr size_t clock_generator_output_r9_sgpio = 1;
|
constexpr size_t clock_generator_output_r9_sgpio = 1;
|
||||||
|
constexpr size_t clock_generator_output_r9_clkout = 2;
|
||||||
constexpr size_t clock_generator_output_r9_mcu_clkin = 2;
|
constexpr size_t clock_generator_output_r9_mcu_clkin = 2;
|
||||||
|
|
||||||
/* ADC0 */
|
/* ADC0 */
|
||||||
|
@@ -77,7 +77,7 @@ constexpr modem_repeat_range_t modem_repeat_range{1, 99};
|
|||||||
constexpr int32_t modem_repeat_reset_value{5};
|
constexpr int32_t modem_repeat_reset_value{5};
|
||||||
|
|
||||||
using clkout_freq_range_t = range_t<uint32_t>;
|
using clkout_freq_range_t = range_t<uint32_t>;
|
||||||
constexpr clkout_freq_range_t clkout_freq_range{10, 60000};
|
constexpr clkout_freq_range_t clkout_freq_range{4, 60000}; // Min. CLK out of Si5351A/B/C-B is 2.5khz , but in our application -intermediate freq 800Mhz-,Min working CLK=4khz.
|
||||||
constexpr uint16_t clkout_freq_reset_value{10000};
|
constexpr uint16_t clkout_freq_reset_value{10000};
|
||||||
|
|
||||||
enum data_structure_version_enum : uint32_t {
|
enum data_structure_version_enum : uint32_t {
|
||||||
@@ -195,6 +195,8 @@ struct data_t {
|
|||||||
|
|
||||||
// Recon App
|
// Recon App
|
||||||
uint64_t recon_config;
|
uint64_t recon_config;
|
||||||
|
int8_t recon_repeat_nb;
|
||||||
|
int8_t recon_repeat_gain;
|
||||||
|
|
||||||
// enable or disable converter
|
// enable or disable converter
|
||||||
bool converter;
|
bool converter;
|
||||||
@@ -257,7 +259,10 @@ struct data_t {
|
|||||||
tone_mix(tone_mix_reset_value),
|
tone_mix(tone_mix_reset_value),
|
||||||
|
|
||||||
hardware_config(0),
|
hardware_config(0),
|
||||||
|
|
||||||
recon_config(0),
|
recon_config(0),
|
||||||
|
recon_repeat_nb(0),
|
||||||
|
recon_repeat_gain(0),
|
||||||
|
|
||||||
converter(false),
|
converter(false),
|
||||||
updown_converter(false),
|
updown_converter(false),
|
||||||
@@ -284,11 +289,11 @@ struct data_t {
|
|||||||
|
|
||||||
struct backup_ram_t {
|
struct backup_ram_t {
|
||||||
private:
|
private:
|
||||||
volatile uint32_t regfile[63];
|
volatile uint32_t regfile[PMEM_SIZE_WORDS - 1];
|
||||||
volatile uint32_t check_value;
|
volatile uint32_t check_value;
|
||||||
|
|
||||||
static void copy(const backup_ram_t& src, backup_ram_t& dst) {
|
static void copy(const backup_ram_t& src, backup_ram_t& dst) {
|
||||||
for (size_t i = 0; i < 63; i++) {
|
for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) {
|
||||||
dst.regfile[i] = src.regfile[i];
|
dst.regfile[i] = src.regfile[i];
|
||||||
}
|
}
|
||||||
dst.check_value = src.check_value;
|
dst.check_value = src.check_value;
|
||||||
@@ -297,7 +302,7 @@ struct backup_ram_t {
|
|||||||
static void copy_from_data_t(const data_t& src, backup_ram_t& dst) {
|
static void copy_from_data_t(const data_t& src, backup_ram_t& dst) {
|
||||||
const uint32_t* const src_words = (uint32_t*)&src;
|
const uint32_t* const src_words = (uint32_t*)&src;
|
||||||
const size_t word_count = (sizeof(data_t) + 3) / 4;
|
const size_t word_count = (sizeof(data_t) + 3) / 4;
|
||||||
for (size_t i = 0; i < 63; i++) {
|
for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) {
|
||||||
if (i < word_count) {
|
if (i < word_count) {
|
||||||
dst.regfile[i] = src_words[i];
|
dst.regfile[i] = src_words[i];
|
||||||
} else {
|
} else {
|
||||||
@@ -308,7 +313,7 @@ struct backup_ram_t {
|
|||||||
|
|
||||||
uint32_t compute_check_value() {
|
uint32_t compute_check_value() {
|
||||||
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
|
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
|
||||||
for (size_t i = 0; i < 63; i++) {
|
for (size_t i = 0; i < PMEM_SIZE_WORDS - 1; i++) {
|
||||||
const auto word = regfile[i];
|
const auto word = regfile[i];
|
||||||
crc.process_byte((word >> 0) & 0xff);
|
crc.process_byte((word >> 0) & 0xff);
|
||||||
crc.process_byte((word >> 8) & 0xff);
|
crc.process_byte((word >> 8) & 0xff);
|
||||||
@@ -391,10 +396,15 @@ void defaults() {
|
|||||||
set_recon_continuous(true);
|
set_recon_continuous(true);
|
||||||
set_recon_clear_output(false);
|
set_recon_clear_output(false);
|
||||||
set_recon_load_freqs(true);
|
set_recon_load_freqs(true);
|
||||||
|
set_recon_load_repeaters(true);
|
||||||
set_recon_load_ranges(true);
|
set_recon_load_ranges(true);
|
||||||
set_recon_update_ranges_when_recon(true);
|
set_recon_update_ranges_when_recon(true);
|
||||||
set_recon_load_hamradios(true);
|
set_recon_load_hamradios(true);
|
||||||
set_recon_match_mode(0);
|
set_recon_match_mode(0);
|
||||||
|
set_recon_repeat_recorded(false);
|
||||||
|
set_recon_repeat_amp(false);
|
||||||
|
set_recon_repeat_gain(35);
|
||||||
|
set_recon_repeat_nb(3);
|
||||||
|
|
||||||
set_config_sdcard_high_speed_io(false, true);
|
set_config_sdcard_high_speed_io(false, true);
|
||||||
}
|
}
|
||||||
@@ -747,6 +757,21 @@ bool recon_match_mode() {
|
|||||||
bool recon_auto_record_locked() {
|
bool recon_auto_record_locked() {
|
||||||
return (data->recon_config & 0x00400000UL) ? true : false;
|
return (data->recon_config & 0x00400000UL) ? true : false;
|
||||||
}
|
}
|
||||||
|
bool recon_repeat_recorded() {
|
||||||
|
return (data->recon_config & 0x00200000UL) ? true : false;
|
||||||
|
}
|
||||||
|
int8_t recon_repeat_nb() {
|
||||||
|
return data->recon_repeat_nb;
|
||||||
|
}
|
||||||
|
int8_t recon_repeat_gain() {
|
||||||
|
return data->recon_repeat_gain;
|
||||||
|
}
|
||||||
|
bool recon_repeat_amp() {
|
||||||
|
return (data->recon_config & 0x00100000UL) ? true : false;
|
||||||
|
}
|
||||||
|
bool recon_load_repeaters() {
|
||||||
|
return (data->recon_config & 0x00080000UL) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
void set_recon_autosave_freqs(const bool v) {
|
void set_recon_autosave_freqs(const bool v) {
|
||||||
data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31);
|
data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31);
|
||||||
@@ -778,6 +803,21 @@ void set_recon_match_mode(const bool v) {
|
|||||||
void set_recon_auto_record_locked(const bool v) {
|
void set_recon_auto_record_locked(const bool v) {
|
||||||
data->recon_config = (data->recon_config & ~0x00400000UL) | (v << 22);
|
data->recon_config = (data->recon_config & ~0x00400000UL) | (v << 22);
|
||||||
}
|
}
|
||||||
|
void set_recon_repeat_recorded(const bool v) {
|
||||||
|
data->recon_config = (data->recon_config & ~0x00200000UL) | (v << 21);
|
||||||
|
}
|
||||||
|
void set_recon_repeat_nb(const int8_t v) {
|
||||||
|
data->recon_repeat_nb = v;
|
||||||
|
}
|
||||||
|
void set_recon_repeat_gain(const int8_t v) {
|
||||||
|
data->recon_repeat_gain = v;
|
||||||
|
}
|
||||||
|
void set_recon_repeat_amp(const bool v) {
|
||||||
|
data->recon_config = (data->recon_config & ~0x00100000UL) | (v << 20);
|
||||||
|
}
|
||||||
|
void set_recon_load_repeaters(const bool v) {
|
||||||
|
data->recon_config = (data->recon_config & ~0x00080000UL) | (v << 19);
|
||||||
|
}
|
||||||
|
|
||||||
/* UI Config 2 */
|
/* UI Config 2 */
|
||||||
bool ui_hide_speaker() {
|
bool ui_hide_speaker() {
|
||||||
|
@@ -39,6 +39,9 @@
|
|||||||
// persistant memory from/to sdcard flag file
|
// persistant memory from/to sdcard flag file
|
||||||
#define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings"
|
#define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings"
|
||||||
|
|
||||||
|
#define PMEM_SIZE_BYTES 256 // total amount of pmem space in bytes, including checksum
|
||||||
|
#define PMEM_SIZE_WORDS (PMEM_SIZE_BYTES / 4)
|
||||||
|
|
||||||
using namespace modems;
|
using namespace modems;
|
||||||
using namespace serializer;
|
using namespace serializer;
|
||||||
|
|
||||||
@@ -242,9 +245,14 @@ bool recon_autostart_recon();
|
|||||||
bool recon_continuous();
|
bool recon_continuous();
|
||||||
bool recon_clear_output();
|
bool recon_clear_output();
|
||||||
bool recon_load_freqs();
|
bool recon_load_freqs();
|
||||||
|
bool recon_load_repeaters();
|
||||||
bool recon_load_ranges();
|
bool recon_load_ranges();
|
||||||
bool recon_update_ranges_when_recon();
|
bool recon_update_ranges_when_recon();
|
||||||
bool recon_auto_record_locked();
|
bool recon_auto_record_locked();
|
||||||
|
bool recon_repeat_recorded();
|
||||||
|
int8_t recon_repeat_nb();
|
||||||
|
int8_t recon_repeat_gain();
|
||||||
|
bool recon_repeat_amp();
|
||||||
bool recon_load_hamradios();
|
bool recon_load_hamradios();
|
||||||
bool recon_match_mode();
|
bool recon_match_mode();
|
||||||
void set_recon_autosave_freqs(const bool v);
|
void set_recon_autosave_freqs(const bool v);
|
||||||
@@ -255,7 +263,12 @@ void set_recon_load_freqs(const bool v);
|
|||||||
void set_recon_load_ranges(const bool v);
|
void set_recon_load_ranges(const bool v);
|
||||||
void set_recon_update_ranges_when_recon(const bool v);
|
void set_recon_update_ranges_when_recon(const bool v);
|
||||||
void set_recon_auto_record_locked(const bool v);
|
void set_recon_auto_record_locked(const bool v);
|
||||||
|
void set_recon_repeat_recorded(const bool v);
|
||||||
|
void set_recon_repeat_nb(const int8_t v);
|
||||||
|
void set_recon_repeat_gain(const int8_t v);
|
||||||
|
void set_recon_repeat_amp(const bool v);
|
||||||
void set_recon_load_hamradios(const bool v);
|
void set_recon_load_hamradios(const bool v);
|
||||||
|
void set_recon_load_repeaters(const bool v);
|
||||||
void set_recon_match_mode(const bool v);
|
void set_recon_match_mode(const bool v);
|
||||||
|
|
||||||
/* UI Config 2 */
|
/* UI Config 2 */
|
||||||
|
@@ -59,6 +59,17 @@ TEST_CASE("It can parse basic ham radio freq entry.") {
|
|||||||
CHECK_EQ(e.type, freqman_type::HamRadio);
|
CHECK_EQ(e.type, freqman_type::HamRadio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("It can parse repeater entry.") {
|
||||||
|
freqman_entry e;
|
||||||
|
REQUIRE(
|
||||||
|
parse_freqman_entry(
|
||||||
|
"l=123000000,t=123000500,d=This is the description.", e));
|
||||||
|
CHECK_EQ(e.frequency_a, 123'000'000);
|
||||||
|
CHECK_EQ(e.frequency_b, 123'000'500);
|
||||||
|
CHECK_EQ(e.description, "This is the description.");
|
||||||
|
CHECK_EQ(e.type, freqman_type::Repeater);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("It can parse modulation") {
|
TEST_CASE("It can parse modulation") {
|
||||||
freqman_entry e;
|
freqman_entry e;
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
@@ -195,6 +206,16 @@ TEST_CASE("It can serialize basic HamRadio entry") {
|
|||||||
CHECK(str == "r=123456000,t=423456000,d=Foobar");
|
CHECK(str == "r=123456000,t=423456000,d=Foobar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("It can serialize basic Repeater entry") {
|
||||||
|
auto str = to_freqman_string(freqman_entry{
|
||||||
|
.frequency_a = 123'456'000,
|
||||||
|
.frequency_b = 423'456'000,
|
||||||
|
.description = "Foobar",
|
||||||
|
.type = freqman_type::Repeater,
|
||||||
|
});
|
||||||
|
CHECK(str == "l=123456000,t=423456000,d=Foobar");
|
||||||
|
}
|
||||||
|
|
||||||
// New tables for a future PR.
|
// New tables for a future PR.
|
||||||
/*
|
/*
|
||||||
TEST_CASE("It can parse modulation") {
|
TEST_CASE("It can parse modulation") {
|
||||||
|
Reference in New Issue
Block a user