mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Merge pull request #104 from euquiq/new-ui-scanner-version
scanner-enhanced-version
This commit is contained in:
commit
4fbdeeab42
@ -26,6 +26,7 @@
|
|||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "audio.hpp"
|
#include "audio.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -38,6 +39,10 @@ ScannerThread::ScannerThread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScannerThread::~ScannerThread() {
|
ScannerThread::~ScannerThread() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScannerThread::stop() {
|
||||||
if( thread ) {
|
if( thread ) {
|
||||||
chThdTerminate(thread);
|
chThdTerminate(thread);
|
||||||
chThdWait(thread);
|
chThdWait(thread);
|
||||||
@ -49,6 +54,18 @@ void ScannerThread::set_scanning(const bool v) {
|
|||||||
_scanning = v;
|
_scanning = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScannerThread::is_scanning() {
|
||||||
|
return _scanning;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScannerThread::set_userpause(const bool v) {
|
||||||
|
_userpause = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScannerThread::is_userpause() {
|
||||||
|
return _userpause;
|
||||||
|
}
|
||||||
|
|
||||||
msg_t ScannerThread::static_fn(void* arg) {
|
msg_t ScannerThread::static_fn(void* arg) {
|
||||||
auto obj = static_cast<ScannerThread*>(arg);
|
auto obj = static_cast<ScannerThread*>(arg);
|
||||||
obj->run();
|
obj->run();
|
||||||
@ -56,36 +73,33 @@ msg_t ScannerThread::static_fn(void* arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScannerThread::run() {
|
void ScannerThread::run() {
|
||||||
RetuneMessage message { };
|
if (frequency_list_.size()) { //IF THERE IS A FREQUENCY LIST ...
|
||||||
uint32_t frequency_index = 0;
|
RetuneMessage message { };
|
||||||
|
uint32_t frequency_index = 0;
|
||||||
|
while( !chThdShouldTerminate() ) {
|
||||||
|
if (_scanning) {
|
||||||
|
// Retune
|
||||||
|
receiver_model.set_tuning_frequency(frequency_list_[frequency_index]);
|
||||||
|
message.range = frequency_index;
|
||||||
|
EventDispatcher::send_message(message);
|
||||||
|
|
||||||
while( !chThdShouldTerminate() ) {
|
frequency_index++;
|
||||||
if (_scanning) {
|
if (frequency_index >= frequency_list_.size())
|
||||||
// Retune
|
frequency_index = 0;
|
||||||
receiver_model.set_tuning_frequency(frequency_list_[frequency_index]);
|
}
|
||||||
|
chThdSleepMilliseconds(50); //50 is enough for reception stabilization, increase for more precise scanning ?
|
||||||
message.range = frequency_index;
|
|
||||||
EventDispatcher::send_message(message);
|
|
||||||
|
|
||||||
|
|
||||||
frequency_index++;
|
|
||||||
if (frequency_index >= frequency_list_.size())
|
|
||||||
frequency_index = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chThdSleepMilliseconds(50);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::handle_retune(uint32_t i) {
|
void ScannerView::handle_retune(uint32_t i) {
|
||||||
text_cycle.set( to_string_dec_uint(i) + "/" +
|
big_display.set(frequency_list[i]); //Show the big Freq
|
||||||
to_string_dec_uint(frequency_list.size()) + " : " +
|
text_cycle.set( to_string_dec_uint(i + 1,3) );
|
||||||
to_string_dec_uint(frequency_list[i]) );
|
if (description_list[i].size() > 0) desc_cycle.set( description_list[i] ); //If this is a new description: show
|
||||||
desc_cycle.set( description_list[i] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::focus() {
|
void ScannerView::focus() {
|
||||||
field_lna.focus();
|
field_mode.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScannerView::~ScannerView() {
|
ScannerView::~ScannerView() {
|
||||||
@ -94,9 +108,16 @@ ScannerView::~ScannerView() {
|
|||||||
baseband::shutdown();
|
baseband::shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScannerView::show_max() { //show total number of freqs to scan
|
||||||
|
if (frequency_list.size() == MAX_DB_ENTRY)
|
||||||
|
text_max.set( "/ " + to_string_dec_uint(MAX_DB_ENTRY) + " (DB MAX!)");
|
||||||
|
else
|
||||||
|
text_max.set( "/ " + to_string_dec_uint(frequency_list.size()));
|
||||||
|
}
|
||||||
|
|
||||||
ScannerView::ScannerView(
|
ScannerView::ScannerView(
|
||||||
NavigationView&
|
NavigationView& nav
|
||||||
)
|
) : nav_ { nav }
|
||||||
{
|
{
|
||||||
add_children({
|
add_children({
|
||||||
&labels,
|
&labels,
|
||||||
@ -105,104 +126,190 @@ ScannerView::ScannerView(
|
|||||||
&field_rf_amp,
|
&field_rf_amp,
|
||||||
&field_volume,
|
&field_volume,
|
||||||
&field_bw,
|
&field_bw,
|
||||||
&field_trigger,
|
|
||||||
&field_squelch,
|
&field_squelch,
|
||||||
&field_wait,
|
&field_wait,
|
||||||
//&record_view,
|
&rssi,
|
||||||
&text_cycle,
|
&text_cycle,
|
||||||
|
&text_max,
|
||||||
&desc_cycle,
|
&desc_cycle,
|
||||||
//&waterfall,
|
&big_display,
|
||||||
|
&button_manual_start,
|
||||||
|
&button_manual_end,
|
||||||
|
&field_mode,
|
||||||
|
&step_mode,
|
||||||
|
&button_manual_scan,
|
||||||
|
&button_pause,
|
||||||
|
&button_audio_app
|
||||||
});
|
});
|
||||||
|
|
||||||
std::string scanner_file = "SCANNER";
|
def_step = change_mode(AM); //Start on AM
|
||||||
if (load_freqman_file(scanner_file, database)) {
|
field_mode.set_by_value(AM); //Reflect the mode into the manual selector
|
||||||
for(auto& entry : database) {
|
|
||||||
// FIXME
|
big_display.set_style(&style_green); //Start with green color
|
||||||
if (entry.type == RANGE) {
|
|
||||||
for (uint32_t i=entry.frequency_a; i < entry.frequency_b; i+= 1000000) {
|
button_manual_start.on_select = [this, &nav](Button& button) {
|
||||||
frequency_list.push_back(i);
|
auto new_view = nav_.push<FrequencyKeypadView>(frequency_range.min);
|
||||||
description_list.push_back("RNG " + to_string_dec_uint(entry.frequency_a) + ">" + to_string_dec_uint(entry.frequency_b));
|
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||||
|
frequency_range.min = f;
|
||||||
|
button_manual_start.set_text(to_string_short_freq(f));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
button_manual_end.on_select = [this, &nav](Button& button) {
|
||||||
|
auto new_view = nav.push<FrequencyKeypadView>(frequency_range.max);
|
||||||
|
new_view->on_changed = [this, &button](rf::Frequency f) {
|
||||||
|
frequency_range.max = f;
|
||||||
|
button_manual_end.set_text(to_string_short_freq(f));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
button_pause.on_select = [this](Button&) {
|
||||||
|
if (scan_thread->is_userpause()) {
|
||||||
|
timer = wait * 10; //Unlock timer pause on_statistics_update
|
||||||
|
button_pause.set_text("PAUSE"); //resume scanning (show button for pause)
|
||||||
|
scan_thread->set_userpause(false);
|
||||||
|
//scan_resume();
|
||||||
|
} else {
|
||||||
|
scan_pause();
|
||||||
|
scan_thread->set_userpause(true);
|
||||||
|
button_pause.set_text("RESUME"); //PAUSED, show resume
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
button_audio_app.on_select = [this](Button&) {
|
||||||
|
if (scan_thread->is_scanning())
|
||||||
|
scan_thread->set_scanning(false);
|
||||||
|
scan_thread->stop();
|
||||||
|
nav_.pop();
|
||||||
|
nav_.push<AnalogAudioView>();
|
||||||
|
};
|
||||||
|
|
||||||
|
button_manual_scan.on_select = [this](Button&) {
|
||||||
|
if (!frequency_range.min || !frequency_range.max) {
|
||||||
|
nav_.display_modal("Error", "Both START and END freqs\nneed a value");
|
||||||
|
} else if (frequency_range.min > frequency_range.max) {
|
||||||
|
nav_.display_modal("Error", "END freq\nis lower than START");
|
||||||
|
} else {
|
||||||
|
scan_thread->stop(); //STOP SCANNER THREAD
|
||||||
|
frequency_list.clear();
|
||||||
|
description_list.clear();
|
||||||
|
def_step = step_mode.selected_index_value(); //Use def_step from manual selector
|
||||||
|
|
||||||
|
description_list.push_back(
|
||||||
|
"M:" + to_string_short_freq(frequency_range.min) + ">"
|
||||||
|
+ to_string_short_freq(frequency_range.max) + " S:"
|
||||||
|
+ to_string_short_freq(def_step)
|
||||||
|
);
|
||||||
|
|
||||||
|
rf::Frequency frequency = frequency_range.min;
|
||||||
|
while (frequency_list.size() < MAX_DB_ENTRY && frequency <= frequency_range.max) { //add manual range
|
||||||
|
frequency_list.push_back(frequency);
|
||||||
|
description_list.push_back(""); //If empty, will keep showing the last description
|
||||||
|
frequency+=def_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
show_max();
|
||||||
|
start_scan_thread(); //RESTART SCANNER THREAD
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
|
||||||
|
if (scan_thread->is_scanning())
|
||||||
|
scan_thread->set_scanning(false); // WE STOP SCANNING
|
||||||
|
audio::output::stop();
|
||||||
|
scan_thread->stop();
|
||||||
|
receiver_model.disable();
|
||||||
|
baseband::shutdown();
|
||||||
|
chThdSleepMilliseconds(50);
|
||||||
|
change_mode(v);
|
||||||
|
start_scan_thread();
|
||||||
|
};
|
||||||
|
|
||||||
|
//PRE-CONFIGURATION:
|
||||||
|
field_wait.on_change = [this](int32_t v) { wait = v; }; field_wait.set_value(5);
|
||||||
|
field_squelch.on_change = [this](int32_t v) { squelch = v; }; field_squelch.set_value(30);
|
||||||
|
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
|
||||||
|
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
|
||||||
|
// LEARN FREQUENCIES
|
||||||
|
std::string scanner_txt = "SCANNER";
|
||||||
|
if ( load_freqman_file(scanner_txt, database) ) {
|
||||||
|
for(auto& entry : database) { // READ LINE PER LINE
|
||||||
|
if (frequency_list.size() < MAX_DB_ENTRY) { //We got space!
|
||||||
|
if (entry.type == RANGE) { //RANGE
|
||||||
|
switch (entry.step) {
|
||||||
|
case AM_US: def_step = 10000; break ;
|
||||||
|
case AM_EUR:def_step = 9000; break ;
|
||||||
|
case NFM_1: def_step = 12500; break ;
|
||||||
|
case NFM_2: def_step = 6250; break ;
|
||||||
|
case FM_1: def_step = 100000; break ;
|
||||||
|
case FM_2: def_step = 50000; break ;
|
||||||
|
case N_1: def_step = 25000; break ;
|
||||||
|
case N_2: def_step = 250000; break ;
|
||||||
|
case AIRBAND:def_step= 8330; break ;
|
||||||
|
}
|
||||||
|
frequency_list.push_back(entry.frequency_a); //Store starting freq and description
|
||||||
|
description_list.push_back("R:" + to_string_short_freq(entry.frequency_a)
|
||||||
|
+ ">" + to_string_short_freq(entry.frequency_b)
|
||||||
|
+ " S:" + to_string_short_freq(def_step));
|
||||||
|
while (frequency_list.size() < MAX_DB_ENTRY && entry.frequency_a <= entry.frequency_b) { //add the rest of the range
|
||||||
|
entry.frequency_a+=def_step;
|
||||||
|
frequency_list.push_back(entry.frequency_a);
|
||||||
|
description_list.push_back(""); //Token (keep showing the last description)
|
||||||
|
}
|
||||||
|
} else if ( entry.type == SINGLE) {
|
||||||
|
frequency_list.push_back(entry.frequency_a);
|
||||||
|
description_list.push_back("S: " + entry.description);
|
||||||
}
|
}
|
||||||
} else {
|
show_max();
|
||||||
frequency_list.push_back(entry.frequency_a);
|
}
|
||||||
description_list.push_back(entry.description);
|
else
|
||||||
|
{
|
||||||
|
break; //No more space: Stop reading the txt file !
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// DEBUG
|
|
||||||
// TODO: Clean this
|
|
||||||
frequency_list.push_back(466025000);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
frequency_list.push_back(466050000);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
frequency_list.push_back(466075000);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
frequency_list.push_back(466175000);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
frequency_list.push_back(466206250);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
frequency_list.push_back(466231250);
|
|
||||||
description_list.push_back("POCSAG-France");
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
field_bw.set_selected_index(2);
|
{
|
||||||
field_bw.on_change = [this](size_t n, OptionsField::value_t) {
|
desc_cycle.set(" NO SCANNER.TXT FILE ..." );
|
||||||
receiver_model.set_nbfm_configuration(n);
|
}
|
||||||
};
|
audio::output::stop();
|
||||||
|
step_mode.set_by_value(def_step); //Impose the default step into the manual step selector
|
||||||
field_wait.on_change = [this](int32_t v) {
|
start_scan_thread();
|
||||||
wait = v;
|
|
||||||
};
|
|
||||||
field_wait.set_value(5);
|
|
||||||
|
|
||||||
field_trigger.on_change = [this](int32_t v) {
|
|
||||||
trigger = v;
|
|
||||||
};
|
|
||||||
field_trigger.set_value(30);
|
|
||||||
|
|
||||||
field_squelch.set_value(receiver_model.squelch_level());
|
|
||||||
field_squelch.on_change = [this](int32_t v) {
|
|
||||||
squelch = v;
|
|
||||||
receiver_model.set_squelch_level(v);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
|
|
||||||
field_volume.on_change = [this](int32_t v) {
|
|
||||||
this->on_headphone_volume_changed(v);
|
|
||||||
};
|
|
||||||
|
|
||||||
audio::output::start();
|
|
||||||
|
|
||||||
audio::output::mute();
|
|
||||||
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
|
|
||||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
|
||||||
receiver_model.set_sampling_rate(3072000);
|
|
||||||
receiver_model.set_baseband_bandwidth(1750000);
|
|
||||||
receiver_model.enable();
|
|
||||||
receiver_model.set_squelch_level(0);
|
|
||||||
receiver_model.set_nbfm_configuration(field_bw.selected_index());
|
|
||||||
audio::output::unmute();
|
|
||||||
|
|
||||||
// TODO: Scanning thread here
|
|
||||||
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScannerView::on_statistics_update(const ChannelStatistics& statistics) {
|
void ScannerView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||||
int32_t max_db = statistics.max_db;
|
if (!scan_thread->is_userpause())
|
||||||
|
{
|
||||||
if (timer <= wait)
|
if (timer >= (wait * 10) )
|
||||||
timer++;
|
{
|
||||||
|
timer=0;
|
||||||
if (max_db < -trigger) {
|
scan_resume();
|
||||||
if (timer == wait) {
|
|
||||||
//audio::output::stop();
|
|
||||||
scan_thread->set_scanning(true);
|
|
||||||
}
|
}
|
||||||
} else {
|
else if (!timer)
|
||||||
//audio::output::start();
|
{
|
||||||
scan_thread->set_scanning(false);
|
if (statistics.max_db > -squelch) { //There is something on the air...
|
||||||
timer = 0;
|
scan_pause();
|
||||||
|
timer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScannerView::scan_pause() {
|
||||||
|
if (scan_thread->is_scanning()) {
|
||||||
|
scan_thread->set_scanning(false); // WE STOP SCANNING
|
||||||
|
audio::output::start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScannerView::scan_resume() {
|
||||||
|
if (!scan_thread->is_scanning()) {
|
||||||
|
audio::output::stop();
|
||||||
|
scan_thread->set_scanning(true); // WE RESCAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,4 +318,60 @@ void ScannerView::on_headphone_volume_changed(int32_t v) {
|
|||||||
receiver_model.set_headphone_volume(new_volume);
|
receiver_model.set_headphone_volume(new_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thread->stop(); After this do a start_scan_thread()
|
||||||
|
using option_t = std::pair<std::string, int32_t>;
|
||||||
|
using options_t = std::vector<option_t>;
|
||||||
|
options_t bw;
|
||||||
|
field_bw.on_change = [this](size_t n, OptionsField::value_t) { };
|
||||||
|
|
||||||
|
switch (new_mod) {
|
||||||
|
case NFM: //bw 16k (2) default
|
||||||
|
bw.emplace_back("8k5", 0);
|
||||||
|
bw.emplace_back("11k", 0);
|
||||||
|
bw.emplace_back("16k", 0);
|
||||||
|
field_bw.set_options(bw);
|
||||||
|
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
|
||||||
|
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||||
|
field_bw.set_selected_index(2);
|
||||||
|
receiver_model.set_nbfm_configuration(field_bw.selected_index());
|
||||||
|
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_nbfm_configuration(n); };
|
||||||
|
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
|
||||||
|
break;
|
||||||
|
case AM:
|
||||||
|
bw.emplace_back("DSB", 0);
|
||||||
|
bw.emplace_back("USB", 0);
|
||||||
|
bw.emplace_back("LSB", 0);
|
||||||
|
field_bw.set_options(bw);
|
||||||
|
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
|
||||||
|
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
|
||||||
|
field_bw.set_selected_index(0);
|
||||||
|
receiver_model.set_am_configuration(field_bw.selected_index());
|
||||||
|
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_am_configuration(n); };
|
||||||
|
receiver_model.set_sampling_rate(2000000);receiver_model.set_baseband_bandwidth(2000000);
|
||||||
|
break;
|
||||||
|
case WFM:
|
||||||
|
bw.emplace_back("16k", 0);
|
||||||
|
field_bw.set_options(bw);
|
||||||
|
|
||||||
|
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||||
|
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||||
|
field_bw.set_selected_index(0);
|
||||||
|
receiver_model.set_wfm_configuration(field_bw.selected_index());
|
||||||
|
field_bw.on_change = [this](size_t n, OptionsField::value_t) { receiver_model.set_wfm_configuration(n); };
|
||||||
|
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(2000000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod_step[new_mod];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScannerView::start_scan_thread() {
|
||||||
|
receiver_model.enable();
|
||||||
|
receiver_model.set_squelch_level(0);
|
||||||
|
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
@ -20,20 +20,38 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
#include "receiver_model.hpp"
|
#include "receiver_model.hpp"
|
||||||
|
|
||||||
#include "ui_receiver.hpp"
|
#include "ui_receiver.hpp"
|
||||||
#include "ui_font_fixed_8x16.hpp"
|
#include "ui_font_fixed_8x16.hpp"
|
||||||
|
#include "ui_spectrum.hpp"
|
||||||
#include "freqman.hpp"
|
#include "freqman.hpp"
|
||||||
|
#include "log_file.hpp"
|
||||||
|
#include "analog_audio_app.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_DB_ENTRY 500
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
enum modulation_type { AM = 0,WFM,NFM };
|
||||||
|
|
||||||
|
string const mod_name[3] = {"AM", "WFM", "NFM"};
|
||||||
|
size_t const mod_step[3] = {9000, 100000, 12500 };
|
||||||
|
|
||||||
class ScannerThread {
|
class ScannerThread {
|
||||||
public:
|
public:
|
||||||
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
||||||
~ScannerThread();
|
~ScannerThread();
|
||||||
|
|
||||||
void set_scanning(const bool v);
|
void set_scanning(const bool v);
|
||||||
|
bool is_scanning();
|
||||||
|
|
||||||
|
void set_userpause(const bool v);
|
||||||
|
bool is_userpause();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
ScannerThread(const ScannerThread&) = delete;
|
ScannerThread(const ScannerThread&) = delete;
|
||||||
ScannerThread(ScannerThread&&) = delete;
|
ScannerThread(ScannerThread&&) = delete;
|
||||||
@ -45,38 +63,64 @@ private:
|
|||||||
Thread* thread { nullptr };
|
Thread* thread { nullptr };
|
||||||
|
|
||||||
bool _scanning { true };
|
bool _scanning { true };
|
||||||
|
bool _userpause { false };
|
||||||
static msg_t static_fn(void* arg);
|
static msg_t static_fn(void* arg);
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScannerView : public View {
|
class ScannerView : public View {
|
||||||
public:
|
public:
|
||||||
ScannerView(NavigationView&);
|
ScannerView(NavigationView& nav);
|
||||||
~ScannerView();
|
~ScannerView();
|
||||||
|
|
||||||
void focus() override;
|
void focus() override;
|
||||||
|
|
||||||
std::string title() const override { return "Scanner"; };
|
void big_display_freq(rf::Frequency f);
|
||||||
|
|
||||||
|
const Style style_grey { // scanning
|
||||||
|
.font = font::fixed_8x16,
|
||||||
|
.background = Color::black(),
|
||||||
|
.foreground = Color::grey(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const Style style_green { //Found signal
|
||||||
|
.font = font::fixed_8x16,
|
||||||
|
.background = Color::black(),
|
||||||
|
.foreground = Color::green(),
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string title() const override { return "SCANNER"; };
|
||||||
|
std::vector<rf::Frequency> frequency_list{ };
|
||||||
|
std::vector<string> description_list { };
|
||||||
|
|
||||||
|
//void set_parent_rect(const Rect new_parent_rect) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NavigationView& nav_;
|
||||||
|
|
||||||
|
void start_scan_thread();
|
||||||
|
size_t change_mode(uint8_t mod_type);
|
||||||
|
void show_max();
|
||||||
|
void scan_pause();
|
||||||
|
void scan_resume();
|
||||||
|
|
||||||
void on_statistics_update(const ChannelStatistics& statistics);
|
void on_statistics_update(const ChannelStatistics& statistics);
|
||||||
void on_headphone_volume_changed(int32_t v);
|
void on_headphone_volume_changed(int32_t v);
|
||||||
void handle_retune(uint32_t i);
|
void handle_retune(uint32_t i);
|
||||||
|
|
||||||
std::vector<rf::Frequency> frequency_list { };
|
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual scan task too...
|
||||||
std::vector<string> description_list { };
|
|
||||||
int32_t trigger { 0 };
|
|
||||||
int32_t squelch { 0 };
|
int32_t squelch { 0 };
|
||||||
uint32_t timer { 0 };
|
uint32_t timer { 0 };
|
||||||
uint32_t wait { 0 };
|
uint32_t wait { 0 };
|
||||||
|
size_t def_step { 0 };
|
||||||
freqman_db database { };
|
freqman_db database { };
|
||||||
|
|
||||||
Labels labels {
|
Labels labels {
|
||||||
{ { 0 * 8, 0 * 16 }, "LNA: TRIGGER: /99 VOL:", Color::light_grey() },
|
{ { 0 * 8, 0 * 16 }, "LNA: VGA: AMP: VOL:", Color::light_grey() },
|
||||||
{ { 0 * 8, 1 * 16 }, "VGA: SQUELCH: /99 AMP:", Color::light_grey() },
|
{ { 0 * 8, 1* 16 }, "BW: SQUELCH: /99 WAIT:", Color::light_grey() },
|
||||||
{ { 0 * 8, 2 * 16 }, " BW: WAIT:", Color::light_grey() },
|
{ { 3 * 8, 10 * 16 }, "START END MANUAL", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 14 * 16 }, "MODE:", Color::light_grey() },
|
||||||
|
{ { 11 * 8, 14 * 16 }, "STEP:", Color::light_grey() },
|
||||||
};
|
};
|
||||||
|
|
||||||
LNAGainField field_lna {
|
LNAGainField field_lna {
|
||||||
@ -84,15 +128,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
VGAGainField field_vga {
|
VGAGainField field_vga {
|
||||||
{ 4 * 8, 1 * 16 }
|
{ 11 * 8, 0 * 16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
RFAmpField field_rf_amp {
|
RFAmpField field_rf_amp {
|
||||||
{ 28 * 8, 1 * 16 }
|
{ 18 * 8, 0 * 16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberField field_volume {
|
NumberField field_volume {
|
||||||
{ 28 * 8, 0 * 16 },
|
{ 24 * 8, 0 * 16 },
|
||||||
2,
|
2,
|
||||||
{ 0, 99 },
|
{ 0, 99 },
|
||||||
1,
|
1,
|
||||||
@ -100,25 +144,13 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
OptionsField field_bw {
|
OptionsField field_bw {
|
||||||
{ 4 * 8, 2 * 16 },
|
{ 3 * 8, 1 * 16 },
|
||||||
3,
|
4,
|
||||||
{
|
{ }
|
||||||
{ "8k5", 0 },
|
|
||||||
{ "11k", 0 },
|
|
||||||
{ "16k", 0 },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NumberField field_trigger {
|
|
||||||
{ 16 * 8, 0 * 16 },
|
|
||||||
2,
|
|
||||||
{ 0, 99 },
|
|
||||||
1,
|
|
||||||
' ',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberField field_squelch {
|
NumberField field_squelch {
|
||||||
{ 16 * 8, 1 * 16 },
|
{ 15 * 8, 1 * 16 },
|
||||||
2,
|
2,
|
||||||
{ 0, 99 },
|
{ 0, 99 },
|
||||||
1,
|
1,
|
||||||
@ -126,20 +158,84 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
NumberField field_wait {
|
NumberField field_wait {
|
||||||
{ 16 * 8, 2 * 16 },
|
{ 26 * 8, 1 * 16 },
|
||||||
2,
|
2,
|
||||||
{ 0, 99 },
|
{ 0, 99 },
|
||||||
1,
|
1,
|
||||||
' ',
|
' ',
|
||||||
};
|
};
|
||||||
|
|
||||||
Text text_cycle {
|
RSSI rssi {
|
||||||
{ 0, 5 * 16, 240, 16 },
|
{ 0 * 16, 2 * 16, 15 * 16, 8 },
|
||||||
"--/--"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Text text_cycle {
|
||||||
|
{ 0, 3 * 16, 3 * 8, 16 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_max {
|
||||||
|
{ 4 * 8, 3 * 16, 18 * 8, 16 },
|
||||||
|
};
|
||||||
|
|
||||||
Text desc_cycle {
|
Text desc_cycle {
|
||||||
{0, 6 * 16, 240, 16 },
|
{0, 4 * 16, 240, 16 },
|
||||||
" "
|
};
|
||||||
|
|
||||||
|
BigFrequency big_display { //Show frequency in glamour
|
||||||
|
{ 4, 6 * 16, 28 * 8, 52 },
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_manual_start {
|
||||||
|
{ 0 * 8, 11 * 16, 11 * 8, 28 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_manual_end {
|
||||||
|
{ 12 * 8, 11 * 16, 11 * 8, 28 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_manual_scan {
|
||||||
|
{ 24 * 8, 11 * 16, 6 * 8, 28 },
|
||||||
|
"SCAN"
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsField field_mode {
|
||||||
|
{ 5 * 8, 14 * 16 },
|
||||||
|
6,
|
||||||
|
{
|
||||||
|
{ " AM ", 0 },
|
||||||
|
{ " WFM ", 1 },
|
||||||
|
{ " NFM ", 2 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsField step_mode {
|
||||||
|
{ 17 * 8, 14 * 16 },
|
||||||
|
12,
|
||||||
|
{
|
||||||
|
{ "5Khz (SA AM)", 5000 },
|
||||||
|
{ "9Khz (EU AM)", 9000 },
|
||||||
|
{ "10Khz(US AM)", 10000 },
|
||||||
|
{ "50Khz (FM1)", 50000 },
|
||||||
|
{ "100Khz(FM2)", 100000 },
|
||||||
|
{ "6.25khz(NFM)", 6250 },
|
||||||
|
{ "12.5khz(NFM)", 12500 },
|
||||||
|
{ "25khz (N1)", 25000 },
|
||||||
|
{ "250khz (N2)", 250000 },
|
||||||
|
{ "8.33khz(AIR)", 8330 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_pause {
|
||||||
|
{ 12, 17 * 16, 96, 24 },
|
||||||
|
"PAUSE"
|
||||||
|
};
|
||||||
|
|
||||||
|
Button button_audio_app {
|
||||||
|
{ 124, 17 * 16, 96, 24 },
|
||||||
|
"AUDIO APP"
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ScannerThread> scan_thread { };
|
std::unique_ptr<ScannerThread> scan_thread { };
|
||||||
|
@ -48,11 +48,28 @@ enum freqman_entry_type {
|
|||||||
RANGE
|
RANGE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Entry step placed for AlainD freqman version (or any other enhanced version)
|
||||||
|
enum freqman_entry_step {
|
||||||
|
STEP_DEF = 0, // default
|
||||||
|
AM_US, // 10 Khz AM/CB
|
||||||
|
AM_EUR, // 9 Khz LW/MW
|
||||||
|
NFM_1, // 12,5 Khz (Analogic PMR 446)
|
||||||
|
NFM_2, // 6,25 Khz (Digital PMR 446)
|
||||||
|
FM_1, // 100 Khz
|
||||||
|
FM_2, // 50 Khz
|
||||||
|
N_1, // 25 Khz
|
||||||
|
N_2, // 250 Khz
|
||||||
|
AIRBAND, // AIRBAND 8,33 Khz
|
||||||
|
ERROR_STEP
|
||||||
|
};
|
||||||
|
|
||||||
|
// freqman_entry_step step added, as above, to provide compatibility / future enhancement.
|
||||||
struct freqman_entry {
|
struct freqman_entry {
|
||||||
rf::Frequency frequency_a { 0 };
|
rf::Frequency frequency_a { 0 };
|
||||||
rf::Frequency frequency_b { 0 };
|
rf::Frequency frequency_b { 0 };
|
||||||
std::string description { };
|
std::string description { };
|
||||||
freqman_entry_type type { };
|
freqman_entry_type type { };
|
||||||
|
freqman_entry_step step { };
|
||||||
};
|
};
|
||||||
|
|
||||||
using freqman_db = std::vector<freqman_entry>;
|
using freqman_db = std::vector<freqman_entry>;
|
||||||
|
@ -113,7 +113,8 @@ std::string to_string_dec_int(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string_short_freq(const uint64_t f) {
|
std::string to_string_short_freq(const uint64_t f) {
|
||||||
auto final_str = to_string_dec_int(f / 1000000, 4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
|
//was... to_string_dec_int(f / 1000000,4)
|
||||||
|
auto final_str = to_string_dec_int(f / 1000000) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
|
||||||
return final_str;
|
return final_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user