Recon record (#1182)

* added auto record checbox and functions (audio and raw)
* Changed baseband compile option from -O3 to -O2. Trying lower gave unexpeted and crashing results.
* added 650k SPEC bw
* fix hang if wait is -100
* fixing no SPEC support in scanner
This commit is contained in:
gullradriel 2023-06-25 08:16:49 +02:00 committed by GitHub
parent e08273b8b8
commit 5cd9c377d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 231 additions and 53 deletions

View File

@ -30,14 +30,26 @@ using portapack::memory::map::backup_ram;
namespace ui { namespace ui {
static RecordView* record_view = NULL;
void ReconView::set_loop_config(bool v) { void ReconView::set_loop_config(bool v) {
continuous = v; continuous = v;
button_loop_config.set_style(v ? &Styles::green : &Styles::white); button_loop_config.set_style(v ? &Styles::green : &Styles::white);
persistent_memory::set_recon_continuous(continuous); persistent_memory::set_recon_continuous(continuous);
} }
void ReconView::recon_stop_recording() {
if (is_recording) {
button_audio_app.set_style(&Styles::white);
record_view->stop();
is_recording = false;
}
}
void ReconView::clear_freqlist_for_ui_action() { void ReconView::clear_freqlist_for_ui_action() {
audio::output::stop(); recon_stop_recording();
if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
// flag to detect and reload frequency_list // flag to detect and reload frequency_list
if (!manual_mode) { if (!manual_mode) {
// clear and shrink_to_fit are not enough to really start with a new, clean, empty vector // clear and shrink_to_fit are not enough to really start with a new, clean, empty vector
@ -232,8 +244,8 @@ bool ReconView::recon_save_config_to_sd() {
make_new_directory(u"SETTINGS"); make_new_directory(u"SETTINGS");
auto result = settings_file.create(RECON_CFG_FILE); auto error = settings_file.create(RECON_CFG_FILE);
if (result.is_valid()) if (error)
return false; return false;
settings_file.write_line(input_file); settings_file.write_line(input_file);
settings_file.write_line(output_file); settings_file.write_line(output_file);
@ -246,7 +258,8 @@ bool ReconView::recon_save_config_to_sd() {
} }
void ReconView::audio_output_start() { void ReconView::audio_output_start() {
audio::output::start(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::start();
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
} }
@ -279,10 +292,6 @@ void ReconView::recon_redraw() {
} else if (freq_lock >= recon_lock_nb_match) { } else if (freq_lock >= recon_lock_nb_match) {
big_display.set_style(&Styles::green); big_display.set_style(&Styles::green);
button_pause.set_text("<UNLOCK>"); button_pause.set_text("<UNLOCK>");
// FREQ IS STRONG: GREEN and recon will pause when on_statistics_update()
if ((!scanner_mode) && autosave && frequency_list.size() > 0) {
recon_save_freq(freq_file_path, current_index, false);
}
} }
} }
if (last_db != db || last_list_size != frequency_list.size()) { if (last_db != db || last_list_size != frequency_list.size()) {
@ -354,16 +363,20 @@ void ReconView::focus() {
} }
ReconView::~ReconView() { ReconView::~ReconView() {
// Save recon config. recon_stop_recording();
delete record_view;
recon_save_config_to_sd(); recon_save_config_to_sd();
if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop(); audio::output::stop();
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
} }
ReconView::ReconView(NavigationView& nav) ReconView::ReconView(NavigationView& nav)
: nav_{nav} { : nav_{nav} {
chrono_start = chTimeNow();
record_view = new RecordView({0, 0, 30 * 8, 1 * 16}, u"AUTO_AUDIO_", u"AUDIO", RecordView::FileType::WAV, 4096, 4);
add_children({&labels, add_children({&labels,
&field_lna, &field_lna,
&field_vga, &field_vga,
@ -399,7 +412,14 @@ ReconView::ReconView(NavigationView& nav)
&button_dir, &button_dir,
&button_restart, &button_restart,
&button_mic_app, &button_mic_app,
&button_remove}); &button_remove,
record_view});
record_view->hidden(true);
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;
// HELPER: Pre-setting a manual range, based on stored frequency // HELPER: Pre-setting a manual range, based on stored frequency
@ -424,6 +444,7 @@ ReconView::ReconView(NavigationView& nav)
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();
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();
button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) { button_manual_start.on_select = [this, &nav](ButtonWithEncoder& button) {
clear_freqlist_for_ui_action(); clear_freqlist_for_ui_action();
@ -680,7 +701,8 @@ ReconView::ReconView(NavigationView& nav)
} else if (frequency_range.min > frequency_range.max) { } else if (frequency_range.min > frequency_range.max) {
nav_.display_modal("Error", "END freq\nis lower than START"); nav_.display_modal("Error", "END freq\nis lower than START");
} else { } else {
audio::output::stop(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
// clear and shrink_to_fit are not enough to really start with a new, clean, empty vector // clear and shrink_to_fit are not enough to really start with a new, clean, empty vector
// swap is the only way to achieve a perfect memory liberation // swap is the only way to achieve a perfect memory liberation
std::vector<freqman_entry>().swap(frequency_list); std::vector<freqman_entry>().swap(frequency_list);
@ -760,6 +782,9 @@ ReconView::ReconView(NavigationView& nav)
button_scanner_mode.set_style(&Styles::blue); button_scanner_mode.set_style(&Styles::blue);
button_scanner_mode.set_text("RECON"); 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&) { // frequency_list[current_index] button_add.on_select = [this](ButtonWithEncoder&) { // frequency_list[current_index]
@ -796,7 +821,8 @@ ReconView::ReconView(NavigationView& nav)
button_config.on_select = [this, &nav](Button&) { button_config.on_select = [this, &nav](Button&) {
clear_freqlist_for_ui_action(); clear_freqlist_for_ui_action();
freq_lock = 0;
timer = 0;
auto open_view = nav.push<ReconSetupView>(input_file, output_file); auto open_view = nav.push<ReconSetupView>(input_file, output_file);
open_view->on_changed = [this](std::vector<std::string> result) { open_view->on_changed = [this](std::vector<std::string> result) {
input_file = result[0]; input_file = result[0];
@ -811,6 +837,7 @@ ReconView::ReconView(NavigationView& nav)
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();
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();
frequency_file_load(false); frequency_file_load(false);
freqlist_cleared_for_ui_action = false; freqlist_cleared_for_ui_action = false;
@ -830,6 +857,9 @@ ReconView::ReconView(NavigationView& nav)
field_wait.on_change = [this](int32_t v) { field_wait.on_change = [this](int32_t v) {
wait = v; wait = v;
// replacing -100 by 200 else it's freezing the device
if (wait == -100)
wait = -200;
colorize_waits(); colorize_waits();
}; };
@ -888,7 +918,8 @@ ReconView::ReconView(NavigationView& nav)
void ReconView::frequency_file_load(bool stop_all_before) { void ReconView::frequency_file_load(bool stop_all_before) {
(void)(stop_all_before); (void)(stop_all_before);
audio::output::stop(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
def_step = step_mode.selected_index(); // use def_step from manual selector def_step = step_mode.selected_index(); // use def_step from manual selector
std::string file_input = input_file; // default recon mode std::string file_input = input_file; // default recon mode
@ -896,29 +927,27 @@ void ReconView::frequency_file_load(bool stop_all_before) {
file_input = output_file; file_input = output_file;
file_name.set_style(&Styles::red); file_name.set_style(&Styles::red);
button_scanner_mode.set_style(&Styles::red); button_scanner_mode.set_style(&Styles::red);
desc_cycle.set_style(&Styles::red);
button_scanner_mode.set_text("SCANNER"); button_scanner_mode.set_text("SCANNER");
} else { } else {
file_name.set_style(&Styles::blue); file_name.set_style(&Styles::blue);
button_scanner_mode.set_style(&Styles::blue); button_scanner_mode.set_style(&Styles::blue);
desc_cycle.set_style(&Styles::blue);
button_scanner_mode.set_text("RECON"); button_scanner_mode.set_text("RECON");
} }
desc_cycle.set_style(&Styles::white);
if (!load_freqman_file(file_input, frequency_list, load_freqs, load_ranges, load_hamradios)) { if (!load_freqman_file(file_input, frequency_list, load_freqs, load_ranges, load_hamradios)) {
file_name.set_style(&Styles::red); file_name.set_style(&Styles::red);
desc_cycle.set_style(&Styles::red);
desc_cycle.set(" NO " + file_input + ".TXT FILE ..."); desc_cycle.set(" NO " + file_input + ".TXT FILE ...");
file_name.set("=> NO DATA"); file_name.set("=> NO DATA");
} else { } else {
file_name.set(file_input + "=>" + output_file); file_name.set(file_input + "=>" + output_file);
if (frequency_list.size() == 0) { if (frequency_list.size() == 0) {
file_name.set_style(&Styles::red); file_name.set_style(&Styles::red);
desc_cycle.set_style(&Styles::red);
desc_cycle.set("/0 no entries in list"); desc_cycle.set("/0 no entries in list");
file_name.set("BadOrEmpty " + file_input); file_name.set("BadOrEmpty " + file_input);
} else { } else {
if (frequency_list.size() > FREQMAN_MAX_PER_FILE) { if (frequency_list.size() > FREQMAN_MAX_PER_FILE) {
file_name.set_style(&Styles::yellow); file_name.set_style(&Styles::yellow);
desc_cycle.set_style(&Styles::yellow);
} }
} }
} }
@ -992,6 +1021,14 @@ void ReconView::frequency_file_load(bool stop_all_before) {
} }
void ReconView::on_statistics_update(const ChannelStatistics& statistics) { void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
systime_t time_interval = 100;
if (field_mode.selected_index_value() == SPEC_MODULATION) {
chrono_end = chTimeNow();
time_interval = chrono_end - chrono_start;
chrono_start = chrono_end;
}
// hack to reload the list if it was cleared by going into CONFIG // hack to reload the list if it was cleared by going into CONFIG
if (freqlist_cleared_for_ui_action) { if (freqlist_cleared_for_ui_action) {
if (!manual_mode) { if (!manual_mode) {
@ -1018,7 +1055,9 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
if (status != 1) { if (status != 1) {
status = 1; status = 1;
if (wait != 0) { if (wait != 0) {
audio::output::stop(); recon_stop_recording();
if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
} }
} }
if (db > squelch) // MATCHING LEVEL if (db > squelch) // MATCHING LEVEL
@ -1040,8 +1079,23 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
if (status != 2) { if (status != 2) {
continuous_lock = false; continuous_lock = false;
status = 2; status = 2;
// FREQ IS STRONG: GREEN and recon will pause when on_statistics_update()
if ((!scanner_mode) && autosave && frequency_list.size() > 0) {
recon_save_freq(freq_file_path, current_index, false);
}
if (wait != 0) { if (wait != 0) {
audio_output_start(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio_output_start();
// contents of a possible recon_start_recording(), but not yet since it's only called once
if (auto_record_locked && !is_recording) {
button_audio_app.set_style(&Styles::red);
record_view->start();
is_recording = true;
}
// FREQ IS STRONG: GREEN and recon will pause when on_statistics_update()
if ((!scanner_mode) && autosave && frequency_list.size() > 0) {
recon_save_freq(freq_file_path, current_index, false);
}
} }
if (wait >= 0) { if (wait >= 0) {
timer = wait; timer = wait;
@ -1060,8 +1114,9 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
text_timer.set("TIMER: " + to_string_dec_int(timer)); text_timer.set("TIMER: " + to_string_dec_int(timer));
} }
if (timer) { if (timer) {
if (!continuous_lock || recon_match_mode == RECON_MATCH_SPARSE) if (!continuous_lock || recon_match_mode == RECON_MATCH_SPARSE) {
timer -= STATS_UPDATE_INTERVAL; timer -= time_interval;
}
if (timer < 0) { if (timer < 0) {
timer = 0; timer = 0;
} }
@ -1072,7 +1127,6 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
if (frequency_list.size() > 0) { if (frequency_list.size() > 0) {
has_looped = false; has_looped = false;
entry_has_changed = false; entry_has_changed = false;
if (recon || stepper != 0 || index_stepper != 0) { if (recon || stepper != 0 || index_stepper != 0) {
if (index_stepper == 0) { if (index_stepper == 0) {
/* we are doing a range */ /* we are doing a range */
@ -1172,7 +1226,8 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
entry_has_changed = true; entry_has_changed = true;
if (!recon) // for some motive, audio output gets stopped. // for some motive, audio output gets stopped.
if (!recon && field_mode.selected_index_value() != SPEC_MODULATION)
audio_output_start(); audio_output_start();
} }
// reload entry if changed // reload entry if changed
@ -1224,7 +1279,8 @@ void ReconView::recon_pause() {
continuous_lock = false; continuous_lock = false;
recon = false; recon = false;
audio_output_start(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio_output_start();
big_display.set_style(&Styles::white); big_display.set_style(&Styles::white);
button_pause.set_text("<RESUME>"); // PAUSED, show resume button_pause.set_text("<RESUME>"); // PAUSED, show resume
@ -1236,7 +1292,8 @@ void ReconView::recon_resume() {
continuous_lock = false; continuous_lock = false;
recon = true; recon = true;
audio::output::stop(); if (field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::stop();
big_display.set_style(&Styles::white); big_display.set_style(&Styles::white);
button_pause.set_text("<PAUSE>"); button_pause.set_text("<PAUSE>");
@ -1277,10 +1334,29 @@ 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) {
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();
if (new_mod != SPEC_MODULATION) {
remove_children({record_view});
delete record_view;
record_view = new RecordView({0, 0, 30 * 8, 1 * 16}, u"AUTO_AUDIO_", u"AUDIO", RecordView::FileType::WAV, 4096, 4);
record_view->set_filename_date_frequency(true);
add_children({record_view});
}
if (new_mod == SPEC_MODULATION) {
audio::output::stop();
remove_children({record_view});
delete record_view;
record_view = new RecordView({0, 0, 30 * 8, 1 * 16}, u"AUTO_RAW_", u"CAPTURES", RecordView::FileType::RawS16, 16384, 3);
record_view->set_filename_date_frequency(true);
add_children({record_view});
}
record_view->hidden(true);
record_view->on_error = [this](std::string message) {
nav_.display_modal("Error", message);
};
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
size_t recording_sampling_rate = 0;
switch (new_mod) { switch (new_mod) {
case AM_MODULATION: case AM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw); freqman_set_bandwidth_option(new_mod, field_bw);
@ -1291,6 +1367,7 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_am_configuration(field_bw.selected_index_value()); 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); }; field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); };
text_ctcss.set(" "); text_ctcss.set(" ");
recording_sampling_rate = 12000;
break; break;
case NFM_MODULATION: case NFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw); freqman_set_bandwidth_option(new_mod, field_bw);
@ -1300,6 +1377,7 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.set_nbfm_configuration(field_bw.selected_index_value()); 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); }; field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); };
recording_sampling_rate = 24000;
break; break;
case WFM_MODULATION: case WFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw); freqman_set_bandwidth_option(new_mod, field_bw);
@ -1310,10 +1388,55 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
receiver_model.set_wfm_configuration(field_bw.selected_index_value()); 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); }; field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
text_ctcss.set(" "); text_ctcss.set(" ");
recording_sampling_rate = 48000;
break;
case SPEC_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
// bw 200k (0) default
baseband::run_image(portapack::spi_flash::image_tag_capture);
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) {
uint32_t anti_alias_baseband_bandwidth_filter = 2500000;
switch (sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
anti_alias_baseband_bandwidth_filter = 1750000; // Minimum BPF MAX2837 for all those lower BW options.
break;
case 4000000 ... 6000000: // BW capture range (500k ... 750kHz max ) fs_max = 8 x 750kHz = 6Mhz
// BW 500k ... 750kHz , ex. 500kHz (fs = 8*BW = 4Mhz) , BW 600kHz (fs = 4,8Mhz) , BW 750 kHz (fs = 6Mhz)
anti_alias_baseband_bandwidth_filter = 2500000; // in some IC MAX2837 appear 2250000 , but both works similar.
break;
case 8800000: // BW capture 1,1Mhz fs = 8 x 1,1Mhz = 8,8Mhz . (1Mhz showed slightly higher noise background).
anti_alias_baseband_bandwidth_filter = 3500000;
break;
case 14000000: // BW capture 1,75Mhz , fs = 8 x 1,75Mhz = 14Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 5000000;
break;
case 16000000: // BW capture 2Mhz , fs = 8 x 2Mhz = 16Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 6000000;
break;
case 20000000: // BW capture 2,5Mhz , fs= 8 x 2,5 Mhz = 20Mhz
// good BPF, good matching, but LCD making flicker , refresh rate should be < 20 Hz , but reasonable picture
anti_alias_baseband_bandwidth_filter = 7000000;
break;
default: // BW capture 2,75Mhz, fs = 8 x 2,75Mhz= 22Mhz max ADC sampling) and others.
// We tested also 9Mhz FPB stightly too much noise floor, better 8Mhz
anti_alias_baseband_bandwidth_filter = 8000000;
}
record_view->set_sampling_rate(sampling_rate);
receiver_model.set_sampling_rate(sampling_rate);
receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter);
};
text_ctcss.set(" ");
break; break;
default: default:
break; break;
} }
if (new_mod != SPEC_MODULATION)
record_view->set_sampling_rate(recording_sampling_rate);
field_mode.set_selected_index(new_mod); field_mode.set_selected_index(new_mod);
field_mode.on_change = [this](size_t, OptionsField::value_t v) { field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) { if (v != -1) {
@ -1321,7 +1444,8 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
} }
}; };
if (!recon) // for some motive, audio output gets stopped. // for some motive, audio output gets stopped.
if (!recon && field_mode.selected_index_value() != SPEC_MODULATION)
audio::output::start(); // so if recon was stopped we resume audio audio::output::start(); // so if recon was stopped we resume audio
receiver_model.enable(); receiver_model.enable();

View File

@ -84,6 +84,8 @@ class ReconView : public View {
bool recon_load_config_from_sd(); bool recon_load_config_from_sd();
bool recon_save_config_to_sd(); bool recon_save_config_to_sd();
bool recon_save_freq(const std::string& freq_file_path, size_t index, bool warn_if_exists); bool recon_save_freq(const std::string& freq_file_path, size_t index, bool warn_if_exists);
// placeholder for possible void recon_start_recording();
void recon_stop_recording();
jammer::jammer_range_t frequency_range{false, 0, MAX_UFREQ}; // perfect for manual recon task too... jammer::jammer_range_t frequency_range{false, 0, MAX_UFREQ}; // perfect for manual recon task too...
int32_t squelch{0}; int32_t squelch{0};
@ -108,6 +110,8 @@ class ReconView : public View {
bool fwd{true}; bool fwd{true};
bool recon{true}; bool recon{true};
bool user_pause{false}; bool user_pause{false};
bool auto_record_locked{false};
bool is_recording{false};
uint32_t recon_lock_nb_match{3}; uint32_t recon_lock_nb_match{3};
uint32_t recon_lock_duration{RECON_MIN_LOCK_DURATION}; uint32_t recon_lock_duration{RECON_MIN_LOCK_DURATION};
uint32_t recon_match_mode{RECON_MATCH_CONTINUOUS}; uint32_t recon_match_mode{RECON_MATCH_CONTINUOUS};
@ -118,10 +122,7 @@ class ReconView : public View {
int32_t index_stepper{0}; int32_t index_stepper{0};
int64_t freq{0}; int64_t freq{0};
uint32_t step{0}; uint32_t step{0};
freqman_index_t def_modulation{0};
freqman_index_t def_bandwidth{0};
freqman_index_t def_step{0}; freqman_index_t def_step{0};
tone_index tone{0};
freqman_entry last_entry{}; freqman_entry last_entry{};
bool entry_has_changed{false}; bool entry_has_changed{false};
uint32_t freq_lock{0}; uint32_t freq_lock{0};
@ -141,13 +142,15 @@ class ReconView : public View {
int32_t last_squelch_index{-1}; int32_t last_squelch_index{-1};
int64_t last_freq{0}; int64_t last_freq{0};
std::string freq_file_path{}; std::string freq_file_path{};
systime_t chrono_start{};
systime_t chrono_end{};
Labels labels{ Labels labels{
{{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()}, {{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()},
{{3 * 8, 8 * 16}, "START END", Color::light_grey()}, {{3 * 8, 8 * 16}, "START END", Color::light_grey()},
{{0 * 8, (22 * 8)}, " S: ", Color::light_grey()}, {{0 * 8, (22 * 8)}, " S: ", Color::light_grey()},
{{0 * 8, (24 * 8) + 4}, "NBLCKS:x W,L: , ", Color::light_grey()}, {{0 * 8, (24 * 8) + 4}, "NBLCKS:x W,L: , ", Color::light_grey()},
{{0 * 8, (26 * 8) + 4}, "MODE: , SQUELCH: ", Color::light_grey()}}; {{0 * 8, (26 * 8) + 4}, "MODE: , SQUELCH: ", Color::light_grey()}};
LNAGainField field_lna{ LNAGainField field_lna{
{4 * 8, 0 * 16}}; {4 * 8, 0 * 16}};
@ -272,11 +275,11 @@ class ReconView : public View {
OptionsField field_mode{ OptionsField field_mode{
{6 * 8, (26 * 8) + 4}, {6 * 8, (26 * 8) + 4},
3, 4,
{}}; {}};
OptionsField field_bw{ OptionsField field_bw{
{10 * 8, (26 * 8) + 4}, {11 * 8, (26 * 8) + 4},
6, 6,
{}}; {}};

View File

@ -103,6 +103,7 @@ void ReconSetupViewMore::save() {
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_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());
}; };
void ReconSetupViewMain::focus() { void ReconSetupViewMain::focus() {
@ -117,12 +118,14 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
add_children({&checkbox_load_freqs, add_children({&checkbox_load_freqs,
&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_load_freqs.set_value(persistent_memory::recon_load_freqs()); checkbox_load_freqs.set_value(persistent_memory::recon_load_freqs());
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());
}; };
void ReconSetupViewMore::focus() { void ReconSetupViewMore::focus() {

View File

@ -132,6 +132,10 @@ class ReconSetupViewMore : public View {
{1 * 8, 102}, {1 * 8, 102},
3, 3,
"auto update m-ranges"}; "auto update m-ranges"};
Checkbox checkbox_auto_record_locked{
{1 * 8, 132},
3,
"auto record locked periods"};
}; };
class ReconSetupView : public View { class ReconSetupView : public View {

View File

@ -447,6 +447,16 @@ ScannerView::ScannerView(
// Mode field was changed (AM/NFM/WFM) // Mode field was changed (AM/NFM/WFM)
field_mode.on_change = [this](size_t, OptionsField::value_t v) { field_mode.on_change = [this](size_t, OptionsField::value_t v) {
static freqman_index_t last_mode = AM_MODULATION;
// unsupported SPEC mode fix
if (v == SPEC_MODULATION) {
if (last_mode == AM_MODULATION)
v = WFM_MODULATION;
else
v = AM_MODULATION;
field_mode.set_selected_index(v);
}
last_mode = v;
receiver_model.disable(); receiver_model.disable();
baseband::shutdown(); baseband::shutdown();
change_mode((freqman_index_t)v); change_mode((freqman_index_t)v);

View File

@ -30,7 +30,8 @@ using options_t = std::vector<option_t>;
options_t freqman_entry_modulations = { options_t freqman_entry_modulations = {
{"AM", 0}, {"AM", 0},
{"NFM", 1}, {"NFM", 1},
{"WFM", 2}}; {"WFM", 2},
{"SPEC", 3}};
options_t freqman_entry_bandwidths[4] = { options_t freqman_entry_bandwidths[4] = {
{// AM {// AM
@ -48,6 +49,25 @@ options_t freqman_entry_bandwidths[4] = {
{"40k", 2}, {"40k", 2},
{"180k", 1}, {"180k", 1},
{"200k", 0}, {"200k", 0},
},
{
// SPEC
{"8k5", 8500},
{"11k", 11000},
{"16k", 16000},
{"25k", 25000},
{"50k", 50000},
{"100k", 100000},
{"250k", 250000},
{"500k", 500000}, /* Previous Limit bandwith Option with perfect micro SD write .C16 format operaton.*/
{"600k", 600000}, /* That extended option is still possible to record with FW version Mayhem v1.41 (< 2,5MB/sec) */
{"650k", 650000},
{"750k", 750000}, /* From this BW onwards, the LCD is ok, but the recorded file is decimated, (not real file size) */
{"1100k", 1100000},
{"1750k", 1750000},
{"2000k", 2000000},
{"2500k", 2500000},
{"2750k", 2750000}, // That is our max Capture option, to keep using later / 8 decimation (22Mhz sampling ADC)
}}; }};
options_t freqman_entry_steps = { options_t freqman_entry_steps = {

View File

@ -59,10 +59,11 @@ enum freqman_entry_type : int8_t {
NOTYPE // undetected NOTYPE // undetected
}; };
enum freqman_entry_modulation : int8_t { enum freqman_entry_modulation : uint8_t {
AM_MODULATION = 0, AM_MODULATION = 0,
NFM_MODULATION, NFM_MODULATION,
WFM_MODULATION, WFM_MODULATION,
SPEC_MODULATION,
}; };
// Entry step placed for AlainD freqman version (or any other enhanced version) // Entry step placed for AlainD freqman version (or any other enhanced version)

View File

@ -32,7 +32,7 @@ include(CheckCXXCompilerFlag)
project(baseband_shared) project(baseband_shared)
# Compiler options here. # Compiler options here.
set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --specs=nano.specs") set(USE_OPT "-O2 -g -falign-functions=16 -fno-math-errno --specs=nano.specs")
# C specific options here (added to USE_OPT). # C specific options here (added to USE_OPT).
set(USE_COPT "-std=gnu99") set(USE_COPT "-std=gnu99")

View File

@ -822,6 +822,9 @@ bool recon_load_hamradios() {
bool recon_match_mode() { bool recon_match_mode() {
return (data->recon_config & 0x00800000UL) ? true : false; return (data->recon_config & 0x00800000UL) ? true : false;
} }
bool recon_auto_record_locked() {
return (data->recon_config & 0x00400000UL) ? 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);
@ -850,6 +853,9 @@ void set_recon_load_hamradios(const bool v) {
void set_recon_match_mode(const bool v) { void set_recon_match_mode(const bool v) {
data->recon_config = (data->recon_config & ~0x00800000UL) | (v << 23); data->recon_config = (data->recon_config & ~0x00800000UL) | (v << 23);
} }
void set_recon_auto_record_locked(const bool v) {
data->recon_config = (data->recon_config & ~0x00400000UL) | (v << 22);
}
/* UI Config 2 */ /* UI Config 2 */
bool ui_hide_speaker() { bool ui_hide_speaker() {
@ -925,25 +931,26 @@ void set_config_converter_freq(int64_t v) {
data->converter_frequency_offset = v; data->converter_frequency_offset = v;
} }
// frequency correction settings // Frequency correction settings
bool config_freq_tx_correction_updown() { bool config_freq_tx_correction_updown() {
return data->updown_frequency_tx_correction; return data->updown_frequency_tx_correction;
} }
void set_freq_tx_correction_updown(bool v) {
data->updown_frequency_tx_correction = v;
}
bool config_freq_rx_correction_updown() { bool config_freq_rx_correction_updown() {
return data->updown_frequency_rx_correction; return data->updown_frequency_rx_correction;
} }
void set_freq_rx_correction_updown(bool v) {
data->updown_frequency_rx_correction = v;
}
uint32_t config_freq_tx_correction() { uint32_t config_freq_tx_correction() {
return data->frequency_tx_correction; return data->frequency_tx_correction;
} }
uint32_t config_freq_rx_correction() { uint32_t config_freq_rx_correction() {
return data->frequency_rx_correction; return data->frequency_rx_correction;
} }
void set_freq_tx_correction_updown(bool v) {
data->updown_frequency_tx_correction = v;
}
void set_freq_rx_correction_updown(bool v) {
data->updown_frequency_rx_correction = v;
}
void set_config_freq_tx_correction(uint32_t v) { void set_config_freq_tx_correction(uint32_t v) {
data->frequency_tx_correction = v; data->frequency_tx_correction = v;
} }
@ -951,7 +958,8 @@ void set_config_freq_rx_correction(uint32_t v) {
data->frequency_rx_correction = v; data->frequency_rx_correction = v;
} }
// rotary encoder dial settings // Rotary encoder dial settings
uint8_t config_encoder_dial_sensitivity() { uint8_t config_encoder_dial_sensitivity() {
return data->encoder_dial_sensitivity; return data->encoder_dial_sensitivity;
} }
@ -959,11 +967,12 @@ void set_encoder_dial_sensitivity(uint8_t v) {
data->encoder_dial_sensitivity = v; data->encoder_dial_sensitivity = v;
} }
// PMem to sdcard settings
bool should_use_sdcard_for_pmem() { bool should_use_sdcard_for_pmem() {
return std::filesystem::file_exists(PMEM_FILEFLAG); return std::filesystem::file_exists(PMEM_FILEFLAG);
} }
// sd persisting settings
int save_persistent_settings_to_file() { int save_persistent_settings_to_file() {
std::string filename = PMEM_SETTING_FILE; std::string filename = PMEM_SETTING_FILE;
delete_file(filename); delete_file(filename);
@ -987,10 +996,14 @@ int load_persistent_settings_from_file() {
return false; return false;
} }
// Pmem size helper
size_t data_size() { size_t data_size() {
return sizeof(data_t); return sizeof(data_t);
} }
// Dump pmem, receiver and transmitter models internals in human readable format
bool debug_dump() { bool debug_dump() {
ui::Painter painter{}; ui::Painter painter{};
std::string debug_dir = "DEBUG"; std::string debug_dir = "DEBUG";
@ -1000,6 +1013,7 @@ bool debug_dump() {
make_new_directory(debug_dir); make_new_directory(debug_dir);
filename = next_filename_matching_pattern(debug_dir + "/DEBUG_DUMP_????.TXT"); filename = next_filename_matching_pattern(debug_dir + "/DEBUG_DUMP_????.TXT");
if (filename.empty()) { if (filename.empty()) {
painter.draw_string({0, 320 - 16}, ui::Styles::red, "COULD NOT GET DUMP NAME !");
return false; return false;
} }
// dump data fo filename // dump data fo filename
@ -1008,7 +1022,6 @@ bool debug_dump() {
painter.draw_string({0, 320 - 16}, ui::Styles::red, "ERROR DUMPING " + filename.filename().string() + " !"); painter.draw_string({0, 320 - 16}, ui::Styles::red, "ERROR DUMPING " + filename.filename().string() + " !");
return false; return false;
} }
// write persistent memory // write persistent memory
pmem_dump_file.write_line("[Persistent Memory]"); pmem_dump_file.write_line("[Persistent Memory]");
@ -1075,7 +1088,6 @@ bool debug_dump() {
// misc_config bits // misc_config bits
pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute())); pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute()));
pmem_dump_file.write_line("misc_config config_speaker_disable: " + to_string_dec_int(config_speaker_disable())); pmem_dump_file.write_line("misc_config config_speaker_disable: " + to_string_dec_int(config_speaker_disable()));
// receiver_model // receiver_model
pmem_dump_file.write_line("[Receiver Model]"); pmem_dump_file.write_line("[Receiver Model]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(receiver_model.target_frequency())); pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(receiver_model.target_frequency()));
@ -1121,9 +1133,8 @@ bool debug_dump() {
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate())); pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate()));
pmem_dump_file.write_line("tx_gain: " + to_string_dec_int(transmitter_model.tx_gain())); pmem_dump_file.write_line("tx_gain: " + to_string_dec_int(transmitter_model.tx_gain()));
pmem_dump_file.write_line("channel_bandwidth: " + to_string_dec_uint(transmitter_model.channel_bandwidth())); pmem_dump_file.write_line("channel_bandwidth: " + to_string_dec_uint(transmitter_model.channel_bandwidth()));
// on screen information
painter.draw_string({0, 320 - 16}, ui::Styles::green, filename.filename().string() + " DUMPED !"); painter.draw_string({0, 320 - 16}, ui::Styles::green, filename.filename().string() + " DUMPED !");
return true; return true;
} }

View File

@ -236,6 +236,7 @@ bool recon_clear_output();
bool recon_load_freqs(); bool recon_load_freqs();
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_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);
@ -245,6 +246,7 @@ void set_recon_clear_output(const bool v);
void set_recon_load_freqs(const bool v); 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_load_hamradios(const bool v); void set_recon_load_hamradios(const bool v);
void set_recon_match_mode(const bool v); void set_recon_match_mode(const bool v);