mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-27 01:49:04 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e02e58b366 | |||
| 37912df085 | |||
| a20a08c630 | |||
| a8885282cd | |||
| 2d9090862b | |||
| 6e5bb7911c | |||
| 46f98ddc8b | |||
| 2902365b80 | |||
| c0f368c978 | |||
| 75c2b69f19 | |||
| 3291c7e2a0 | |||
| 64ca9f6a68 | |||
| 297063873f | |||
| 1f7b800c2a |
@@ -51,6 +51,13 @@ int app_settings::load(std::string application, AppSettings* settings) {
|
||||
settings->tx_amp=std::app_settings::read_long_long(file_content, "tx_amp=");
|
||||
settings->tx_frequency=std::app_settings::read_long_long(file_content, "tx_frequency=");
|
||||
settings->tx_gain=std::app_settings::read_long_long(file_content, "tx_gain=");
|
||||
settings->step=std::app_settings::read_long_long(file_content, "step=");
|
||||
settings->modulation=std::app_settings::read_long_long(file_content, "modulation=");
|
||||
settings->am_config_index=std::app_settings::read_long_long(file_content, "am_config_index=");
|
||||
settings->nbfm_config_index=std::app_settings::read_long_long(file_content, "nbfm_config_index=");
|
||||
settings->wfm_config_index=std::app_settings::read_long_long(file_content, "wfm_config_index=");
|
||||
settings->squelch=std::app_settings::read_long_long(file_content, "squelch=");
|
||||
|
||||
rc = SETTINGS_OK;
|
||||
}
|
||||
else rc = SETTINGS_UNABLE_TO_LOAD;
|
||||
@@ -61,7 +68,7 @@ int app_settings::load(std::string application, AppSettings* settings) {
|
||||
|
||||
int app_settings::save(std::string application, AppSettings* settings) {
|
||||
|
||||
if (portapack::persistent_memory::save_app_settings()) {
|
||||
if (portapack::persistent_memory::save_app_settings()) {
|
||||
file_path = folder+"/"+application+".ini";
|
||||
make_new_directory(folder);
|
||||
|
||||
@@ -79,6 +86,12 @@ int app_settings::save(std::string application, AppSettings* settings) {
|
||||
// Save other settings from struct
|
||||
settings_file.write_line("rx_frequency="+to_string_dec_uint(settings->rx_frequency));
|
||||
settings_file.write_line("tx_frequency="+to_string_dec_uint(settings->tx_frequency));
|
||||
settings_file.write_line("step="+to_string_dec_uint(settings->step));
|
||||
settings_file.write_line("modulation="+to_string_dec_uint(settings->modulation));
|
||||
settings_file.write_line("am_config_index="+to_string_dec_uint(settings->am_config_index));
|
||||
settings_file.write_line("nbfm_config_index="+to_string_dec_uint(settings->nbfm_config_index));
|
||||
settings_file.write_line("wfm_config_index="+to_string_dec_uint(settings->wfm_config_index));
|
||||
settings_file.write_line("squelch="+to_string_dec_uint(settings->squelch));
|
||||
|
||||
rc = SETTINGS_OK;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,11 @@ public:
|
||||
uint32_t tx_frequency;
|
||||
uint8_t tx_gain;
|
||||
uint8_t vga;
|
||||
uint32_t step;
|
||||
uint8_t am_config_index;
|
||||
uint8_t nbfm_config_index;
|
||||
uint8_t wfm_config_index;
|
||||
uint8_t squelch;
|
||||
};
|
||||
|
||||
int load(std::string application, AppSettings* settings);
|
||||
|
||||
@@ -136,6 +136,7 @@ AnalogAudioView::AnalogAudioView(
|
||||
field_vga.set_value(app_settings.vga);
|
||||
receiver_model.set_rf_amp(app_settings.rx_amp);
|
||||
field_frequency.set_value(app_settings.rx_frequency);
|
||||
receiver_model.set_configuration_without_init(static_cast<ReceiverModel::Mode>(app_settings.modulation), app_settings.step, app_settings.am_config_index, app_settings.nbfm_config_index, app_settings.wfm_config_index, app_settings.squelch);
|
||||
}
|
||||
else field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
|
||||
@@ -193,36 +194,45 @@ AnalogAudioView::AnalogAudioView(
|
||||
audio::output::start();
|
||||
|
||||
update_modulation(static_cast<ReceiverModel::Mode>(modulation));
|
||||
on_modulation_changed(static_cast<ReceiverModel::Mode>(modulation));
|
||||
on_modulation_changed(static_cast<ReceiverModel::Mode>(modulation));
|
||||
}
|
||||
|
||||
size_t AnalogAudioView::get_spec_bw_index() {
|
||||
return spec_bw_index;
|
||||
return spec_bw_index;
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_spec_bw(size_t index, uint32_t bw) {
|
||||
spec_bw_index = index;
|
||||
spec_bw = bw;
|
||||
spec_bw_index = index;
|
||||
spec_bw = bw;
|
||||
|
||||
baseband::set_spectrum(bw, spec_trigger);
|
||||
receiver_model.set_sampling_rate(bw);
|
||||
receiver_model.set_baseband_bandwidth(bw/2);
|
||||
baseband::set_spectrum(bw, spec_trigger);
|
||||
receiver_model.set_sampling_rate(bw);
|
||||
receiver_model.set_baseband_bandwidth(bw/2);
|
||||
}
|
||||
|
||||
uint16_t AnalogAudioView::get_spec_trigger() {
|
||||
return spec_trigger;
|
||||
return spec_trigger;
|
||||
}
|
||||
|
||||
void AnalogAudioView::set_spec_trigger(uint16_t trigger) {
|
||||
spec_trigger = trigger;
|
||||
spec_trigger = trigger;
|
||||
|
||||
baseband::set_spectrum(spec_bw, spec_trigger);
|
||||
baseband::set_spectrum(spec_bw, spec_trigger);
|
||||
}
|
||||
|
||||
AnalogAudioView::~AnalogAudioView() {
|
||||
|
||||
// save app settings
|
||||
app_settings.rx_frequency = field_frequency.value();
|
||||
app_settings.lna = receiver_model.lna();
|
||||
app_settings.vga = receiver_model.vga();
|
||||
app_settings.rx_amp = receiver_model.rf_amp();
|
||||
app_settings.step = receiver_model.frequency_step();
|
||||
app_settings.modulation = (uint8_t)receiver_model.modulation();
|
||||
app_settings.am_config_index = receiver_model.am_configuration();
|
||||
app_settings.nbfm_config_index = receiver_model.nbfm_configuration();
|
||||
app_settings.wfm_config_index = receiver_model.wfm_configuration();
|
||||
app_settings.squelch = receiver_model.squelch_level();
|
||||
settings.save("rx_audio", &app_settings);
|
||||
|
||||
// TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do
|
||||
|
||||
@@ -162,13 +162,16 @@ ADSBSpeedView::ADSBSpeedView(
|
||||
|
||||
add_children({
|
||||
&labels_speed,
|
||||
&labels_vert_rate,
|
||||
&compass,
|
||||
&field_angle,
|
||||
&field_speed
|
||||
&field_speed,
|
||||
&field_vert_rate
|
||||
});
|
||||
|
||||
field_angle.set_value(0);
|
||||
field_speed.set_value(400);
|
||||
field_vert_rate.set_value(0);
|
||||
|
||||
field_angle.on_change = [this](int32_t v) {
|
||||
compass.set_value(v);
|
||||
@@ -181,7 +184,7 @@ void ADSBSpeedView::collect_frames(const uint32_t ICAO_address, std::vector<ADSB
|
||||
ADSBFrame temp_frame;
|
||||
|
||||
encode_frame_velo(temp_frame, ICAO_address, field_speed.value(),
|
||||
field_angle.value(), 0); // TODO: v_rate
|
||||
field_angle.value(), field_vert_rate.value()); // Added v_rate , ft/min , (+) climb , (-) descend .
|
||||
|
||||
frame_list.emplace_back(temp_frame);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,10 @@ private:
|
||||
{ { 1 * 8, 6 * 16 }, "Speed: kn Bearing: *", Color::light_grey() }
|
||||
};
|
||||
|
||||
Labels labels_vert_rate {
|
||||
{ { 1 * 8, 8 * 16 }, "Vert. rate: ft/min, (+/-)", Color::light_grey() }
|
||||
};
|
||||
|
||||
Compass compass {
|
||||
{ 21 * 8, 2 * 16 }
|
||||
};
|
||||
@@ -107,6 +111,10 @@ private:
|
||||
NumberField field_speed {
|
||||
{ 8 * 8, 6 * 16 }, 3, { 0, 999 }, 5, ' '
|
||||
};
|
||||
|
||||
NumberField field_vert_rate {
|
||||
{ 11 * 8, 8 * 16 }, 5, { -4096, 4096 }, 64, ' ' // Let's limit to +/-5k aprox , Ex. max safe descent vertical rate aprox -1000 ft/min on an instrument approach. , std step is 64
|
||||
};
|
||||
};
|
||||
|
||||
class ADSBSquawkView : public OptionTabView {
|
||||
|
||||
@@ -31,13 +31,23 @@ ScannerThread::ScannerThread(
|
||||
std::vector<rf::Frequency> frequency_list
|
||||
) : frequency_list_ { std::move(frequency_list) }
|
||||
{
|
||||
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ScannerThread::static_fn, this);
|
||||
create_thread();
|
||||
}
|
||||
|
||||
ScannerThread::ScannerThread(const jammer::jammer_range_t& frequency_range, size_t def_step) : frequency_range_(frequency_range), def_step_(def_step)
|
||||
{
|
||||
create_thread();
|
||||
}
|
||||
|
||||
ScannerThread::~ScannerThread() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void ScannerThread::create_thread()
|
||||
{
|
||||
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ScannerThread::static_fn, this);
|
||||
}
|
||||
|
||||
void ScannerThread::stop() {
|
||||
if( thread ) {
|
||||
chThdTerminate(thread);
|
||||
@@ -102,12 +112,13 @@ void ScannerThread::run() {
|
||||
else
|
||||
restart_scan=false; //Effectively skipping first retuning, giving system time
|
||||
}
|
||||
message.freq = frequency_list_[frequency_index];
|
||||
message.range = frequency_index; //Inform freq (for coloring purposes also!)
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
else { //NOT scanning
|
||||
if (_freq_del != 0) { //There is a frequency to delete
|
||||
for (uint16_t i = 0; i < frequency_list_.size(); i++) { //Search for the freq to delete
|
||||
for (uint32_t i = 0; i < frequency_list_.size(); i++) { //Search for the freq to delete
|
||||
if (frequency_list_[i] == _freq_del)
|
||||
{ //found: Erase it
|
||||
frequency_list_.erase(frequency_list_.begin() + i);
|
||||
@@ -126,16 +137,58 @@ void ScannerThread::run() {
|
||||
}
|
||||
chThdSleepMilliseconds(50); //Needed to (eventually) stabilize the receiver into new freq
|
||||
}
|
||||
}else if(def_step_ > 0) // manual mode
|
||||
{
|
||||
RetuneMessage message { };
|
||||
int64_t frequency_index = 0;
|
||||
int64_t size = (frequency_range_.max - frequency_range_.min) / def_step_;
|
||||
bool restart_scan = false; //Flag whenever scanning is restarting after a pause
|
||||
while( !chThdShouldTerminate() ) {
|
||||
if (_scanning) { //Scanning
|
||||
if (_freq_lock == 0) { //normal scanning (not performing freq_lock)
|
||||
if (!restart_scan) { //looping at full speed
|
||||
if (_fwd) { //forward
|
||||
frequency_index++;
|
||||
if (frequency_index >= size)
|
||||
frequency_index = 0;
|
||||
|
||||
} else { //reverse
|
||||
if (frequency_index < 1)
|
||||
frequency_index = size;
|
||||
frequency_index--;
|
||||
}
|
||||
receiver_model.set_tuning_frequency(frequency_range_.min + frequency_index * def_step_); // Retune
|
||||
}
|
||||
else
|
||||
restart_scan=false; //Effectively skipping first retuning, giving system time
|
||||
}
|
||||
message.freq = frequency_range_.min + frequency_index * def_step_;
|
||||
message.range = 0; //Inform freq (for coloring purposes also!)
|
||||
EventDispatcher::send_message(message);
|
||||
}
|
||||
else { //NOT scanning
|
||||
restart_scan=true; //Flag the need for skipping a cycle when restarting scan
|
||||
}
|
||||
chThdSleepMilliseconds(50); //Needed to (eventually) stabilize the receiver into new freq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScannerView::handle_retune(uint32_t i) {
|
||||
void ScannerView::handle_retune(int64_t freq, uint32_t freq_idx) {
|
||||
|
||||
current_index = freq_idx; //since it is an ongoing scan, this is a new index
|
||||
current_frequency = freq;
|
||||
|
||||
switch (scan_thread->is_freq_lock())
|
||||
{
|
||||
case 0: //NO FREQ LOCK, ONGOING STANDARD SCANNING
|
||||
text_cycle.set( to_string_dec_uint(i + 1,3) );
|
||||
current_index = i; //since it is an ongoing scan, this is a new index
|
||||
if (description_list[current_index].size() > 0) desc_cycle.set( description_list[current_index] ); //Show new description
|
||||
if (frequency_list.size() > 0) {
|
||||
text_cycle.set( to_string_dec_uint(freq_idx + 1,3) );
|
||||
}
|
||||
|
||||
if (freq_idx < description_list.size() && description_list[freq_idx].size() > 0) {
|
||||
desc_cycle.set( description_list[freq_idx] ); //Show new description
|
||||
}
|
||||
break;
|
||||
case 1: //STARTING LOCK FREQ
|
||||
big_display.set_style(&style_yellow);
|
||||
@@ -146,7 +199,7 @@ void ScannerView::handle_retune(uint32_t i) {
|
||||
default: //freq lock is checking the signal, do not update display
|
||||
return;
|
||||
}
|
||||
big_display.set(frequency_list[current_index]); //UPDATE the big Freq after 0, 1 or MAX_FREQ_LOCK (at least, for color synching)
|
||||
big_display.set(freq); //UPDATE the big Freq after 0, 1 or MAX_FREQ_LOCK (at least, for color synching)
|
||||
}
|
||||
|
||||
void ScannerView::focus() {
|
||||
@@ -154,6 +207,8 @@ void ScannerView::focus() {
|
||||
}
|
||||
|
||||
ScannerView::~ScannerView() {
|
||||
// make sure to stop the thread before shutting down the receiver
|
||||
scan_thread.reset();
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
@@ -297,23 +352,15 @@ ScannerView::ScannerView(
|
||||
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).erase(0,1) //euquiq: lame kludge to reduce spacing in step freq
|
||||
);
|
||||
|
||||
rf::Frequency frequency = frequency_range.min;
|
||||
while (frequency_list.size() < FREQMAN_MAX_PER_FILE && 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();
|
||||
desc_cycle.set("");
|
||||
text_max.set("");
|
||||
text_cycle.set("");
|
||||
|
||||
if ( userpause ) //If user-paused, resume
|
||||
user_resume();
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
start_scan_thread(); //RESTART SCANNER THREAD
|
||||
start_scan_thread(frequency_range, def_step); //RESTART SCANNER THREAD
|
||||
}
|
||||
};
|
||||
|
||||
@@ -333,35 +380,56 @@ ScannerView::ScannerView(
|
||||
big_display.set_style(&style_grey); //Back to grey color
|
||||
};
|
||||
|
||||
button_add.on_select = [this](Button&) { //frequency_list[current_index]
|
||||
|
||||
button_add.on_select = [this](Button&) { // current_frequency
|
||||
|
||||
File scanner_file;
|
||||
std::string freq_file_path = "FREQMAN/" + loaded_file_name + ".TXT";
|
||||
const std::string freq_file_path = "FREQMAN/" + loaded_file_name + ".TXT";
|
||||
auto result = scanner_file.open(freq_file_path); //First search if freq is already in txt
|
||||
|
||||
if (!result.is_valid()) {
|
||||
std::string frequency_to_add = "f="
|
||||
+ to_string_dec_uint(frequency_list[current_index] / 1000)
|
||||
+ to_string_dec_uint(frequency_list[current_index] % 1000UL, 3, '0');
|
||||
char one_char[1]; //Read it char by char
|
||||
std::string line; //and put read line in here
|
||||
const std::string frequency_to_add = "f="
|
||||
+ to_string_dec_uint(current_frequency / 1000)
|
||||
+ to_string_dec_uint(current_frequency % 1000UL, 3, '0');
|
||||
|
||||
bool found=false;
|
||||
for (size_t pointer=0; pointer < scanner_file.size();pointer++) {
|
||||
constexpr size_t buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
|
||||
for (size_t pointer = 0, freq_str_idx = 0; pointer < scanner_file.size(); pointer += buffer_size) {
|
||||
size_t adjusted_buffer_size;
|
||||
if (pointer + buffer_size >= scanner_file.size()) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
adjusted_buffer_size = scanner_file.size() - pointer;
|
||||
}
|
||||
else {
|
||||
adjusted_buffer_size = buffer_size;
|
||||
}
|
||||
|
||||
scanner_file.seek(pointer);
|
||||
scanner_file.read(one_char, 1);
|
||||
if ((int)one_char[0] > 31) { //ascii space upwards
|
||||
line += one_char[0]; //Add it to the textline
|
||||
}
|
||||
else if (one_char[0] == '\n') { //New Line
|
||||
if (line.compare(0, frequency_to_add.size(),frequency_to_add) == 0) {
|
||||
found=true;
|
||||
break;
|
||||
scanner_file.read(buffer, adjusted_buffer_size);
|
||||
|
||||
for (size_t i = 0; i < adjusted_buffer_size; ++i) {
|
||||
if (buffer[i] == frequency_to_add.data()[freq_str_idx]) {
|
||||
++freq_str_idx;
|
||||
if (freq_str_idx >= frequency_to_add.size()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
freq_str_idx = 0;
|
||||
}
|
||||
line.clear(); //Ready for next textline
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
nav_.display_modal("Error", "Frequency already exists");
|
||||
big_display.set(frequency_list[current_index]); //After showing an error
|
||||
big_display.set(current_frequency); //After showing an error
|
||||
}
|
||||
else {
|
||||
scanner_file.append(freq_file_path); //Second: append if it is not there
|
||||
@@ -370,7 +438,7 @@ ScannerView::ScannerView(
|
||||
} else
|
||||
{
|
||||
nav_.display_modal("Error", "Cannot open " + loaded_file_name + ".TXT\nfor appending freq.");
|
||||
big_display.set(frequency_list[current_index]); //After showing an error
|
||||
big_display.set(current_frequency); //After showing an error
|
||||
}
|
||||
};
|
||||
|
||||
@@ -516,9 +584,9 @@ size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thre
|
||||
|
||||
switch (new_mod) {
|
||||
case NFM: //bw 16k (2) default
|
||||
bw.emplace_back("8k5", 0);
|
||||
bw.emplace_back("11k", 0);
|
||||
bw.emplace_back("16k", 0);
|
||||
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);
|
||||
@@ -545,7 +613,7 @@ size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thre
|
||||
receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000);
|
||||
break;
|
||||
case WFM:
|
||||
bw.emplace_back("200k", 0);
|
||||
bw.emplace_back("200k ", 0);
|
||||
field_bw.set_options(bw);
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||
@@ -566,4 +634,10 @@ void ScannerView::start_scan_thread() {
|
||||
scan_thread = std::make_unique<ScannerThread>(frequency_list);
|
||||
}
|
||||
|
||||
void ScannerView::start_scan_thread(const jammer::jammer_range_t& frequency_range, size_t def_step) {
|
||||
receiver_model.enable();
|
||||
receiver_model.set_squelch_level(0);
|
||||
scan_thread = std::make_unique<ScannerThread>(frequency_range, def_step);
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
@@ -46,6 +46,7 @@ size_t const mod_step[3] = {9000, 100000, 12500 };
|
||||
class ScannerThread {
|
||||
public:
|
||||
ScannerThread(std::vector<rf::Frequency> frequency_list);
|
||||
ScannerThread(const jammer::jammer_range_t& frequency_range, size_t def_step);
|
||||
~ScannerThread();
|
||||
|
||||
void set_scanning(const bool v);
|
||||
@@ -67,6 +68,8 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<rf::Frequency> frequency_list_ { };
|
||||
jammer::jammer_range_t frequency_range_ {false, 0, 0};
|
||||
size_t def_step_ { 0 };
|
||||
Thread* thread { nullptr };
|
||||
|
||||
bool _scanning { true };
|
||||
@@ -75,6 +78,7 @@ private:
|
||||
uint32_t _freq_del { 0 };
|
||||
static msg_t static_fn(void* arg);
|
||||
void run();
|
||||
void create_thread();
|
||||
};
|
||||
|
||||
class ScannerView : public View {
|
||||
@@ -120,6 +124,7 @@ private:
|
||||
NavigationView& nav_;
|
||||
|
||||
void start_scan_thread();
|
||||
void start_scan_thread(const jammer::jammer_range_t& frequency_range, size_t def_step);
|
||||
size_t change_mode(uint8_t mod_type);
|
||||
void show_max();
|
||||
void scan_pause();
|
||||
@@ -129,7 +134,7 @@ private:
|
||||
|
||||
void on_statistics_update(const ChannelStatistics& statistics);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
void handle_retune(uint32_t i);
|
||||
void handle_retune(int64_t freq, uint32_t freq_idx);
|
||||
|
||||
jammer::jammer_range_t frequency_range { false, 0, 0 }; //perfect for manual scan task too...
|
||||
int32_t squelch { 0 };
|
||||
@@ -139,6 +144,7 @@ private:
|
||||
freqman_db database { };
|
||||
std::string loaded_file_name;
|
||||
uint32_t current_index { 0 };
|
||||
rf::Frequency current_frequency { 0 };
|
||||
bool userpause { false };
|
||||
|
||||
Labels labels {
|
||||
@@ -295,7 +301,7 @@ private:
|
||||
Message::ID::Retune,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const RetuneMessage*>(p);
|
||||
this->handle_retune(message.range);
|
||||
this->handle_retune(message.freq, message.range);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -313,3 +313,12 @@ size_t ReceiverModel::wfm_configuration() const {
|
||||
void ReceiverModel::update_wfm_configuration() {
|
||||
wfm_configs[wfm_config_index].apply();
|
||||
}
|
||||
|
||||
void ReceiverModel::set_configuration_without_init(const Mode new_mode, const rf::Frequency new_frequency_step, const size_t new_am_config_index, const size_t new_nbfm_config_index, const size_t new_wfm_config_index, uint8_t new_squelch_level) {
|
||||
mode_ = new_mode;
|
||||
frequency_step_ = new_frequency_step;
|
||||
am_config_index = new_am_config_index;
|
||||
nbfm_config_index = new_nbfm_config_index;
|
||||
wfm_config_index = new_wfm_config_index;
|
||||
squelch_level_ = new_squelch_level;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ public:
|
||||
size_t wfm_configuration() const;
|
||||
void set_wfm_configuration(const size_t n);
|
||||
|
||||
void set_configuration_without_init(const Mode new_mode, const rf::Frequency new_frequency_step, const size_t new_am_config_index, const size_t new_nbfm_config_index, const size_t new_wfm_config_index, uint8_t new_squelch_level);
|
||||
|
||||
private:
|
||||
rf::Frequency frequency_step_ { 25000 };
|
||||
bool enabled_ { false };
|
||||
|
||||
+17
-10
@@ -307,26 +307,33 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
|
||||
const float angle, const int32_t v_rate) {
|
||||
|
||||
int32_t velo_ew, velo_ns, v_rate_coded;
|
||||
int32_t velo_ew, velo_ns;
|
||||
uint32_t velo_ew_abs, velo_ns_abs, v_rate_coded_abs;
|
||||
|
||||
// To get NS and EW speeds from speed and bearing, a polar to cartesian conversion is enough
|
||||
velo_ew = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle) + (pi / 2)) * speed);
|
||||
velo_ns = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle)) * speed);
|
||||
velo_ew = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle) ) * speed); // East direction, is the projection from West -> East is directly sin(angle=Compas Bearing) , (90º is the max +1, EAST) max velo_EW
|
||||
velo_ns = static_cast<int32_t>(sin_f32( (pi/2 - DEG_TO_RAD(angle) ) ) * speed); // North direction,is the projection of North = cos(angle=Compas Bearing), cos(angle)= sen(90-angle) (0º is the max +1 NORTH) max velo_NS
|
||||
|
||||
v_rate_coded = (v_rate / 64) + 1;
|
||||
|
||||
velo_ew_abs = abs(velo_ew) + 1;
|
||||
velo_ns_abs = abs(velo_ns) + 1;
|
||||
v_rate_coded_abs = abs(v_rate_coded);
|
||||
v_rate_coded_abs = (abs(v_rate) / 64) + 1; //encoding vertical rate source. (Decoding, VR ft/min = (Decimal v_rate_value - 1)* 64)
|
||||
|
||||
velo_ew_abs = abs(velo_ew) + 1; // encoding Velo speed EW , when sign Direction is 0 (+): West->East, (-) 1: East->West
|
||||
velo_ns_abs = abs(velo_ns) + 1; // encoding Velo speed NS , when sign Direction is 0 (+): South->North , (-) 1: North->South
|
||||
|
||||
make_frame_adsb(frame, ICAO_address);
|
||||
|
||||
frame.push_byte((TC_AIRBORNE_VELO << 3) | 1); // Subtype: 1 (subsonic)
|
||||
// Airborne velocities are all transmitted with Type Code 19 ( TC=19, using 5 bits ,TC=19 [Binary: 10011]), the following 3 bits are Subt-type Code ,SC= 1,2,3,4
|
||||
// SC Subtypes code 1 and 2 are used to report ground speeds of aircraft. (SC 3,4 to used to report true airspeed. SC 2,4 are for supersonic aircraft (not used in commercial airline).
|
||||
frame.push_byte((TC_AIRBORNE_VELO << 3) | 1); // 1st byte , top 5 bits Type Code TC=19, and lower 3 bits (38-40 bits), SC=001 Subtype Code SC: 1 (subsonic) ,
|
||||
|
||||
// Message A, (ME bits from 14-35) , 22 bits = Sign ew(1 bit) + V_ew (10 bits) + Sign_ns (1 bit) + V_ns (10 bits)
|
||||
// Vertical rate source bit VrSrc (ME bit 36) indicates source of the altitude measurements. GNSS altitude(0) / , barometric altitude(1).
|
||||
// Vertical rate source direction,(ME bit 37) movement can be read from Svr bit , with 0 and 1 referring to climb and descent, respectively (ft/min)
|
||||
// The encoded vertical rate value VR can be computed using message (ME bits 38 to 46). If the 9-bit block contains all zeros, the vertical rate information is not available.
|
||||
// + Sign VrSrc (vert rate src) (1 bit)+ VrSrc (9 bits).
|
||||
frame.push_byte(((velo_ew < 0 ? 1 : 0) << 2) | (velo_ew_abs >> 8));
|
||||
frame.push_byte(velo_ew_abs);
|
||||
frame.push_byte(((velo_ns < 0 ? 1 : 0) << 7) | (velo_ns_abs >> 3));
|
||||
frame.push_byte((velo_ns_abs << 5) | ((v_rate_coded < 0 ? 1 : 0) << 3) | (v_rate_coded_abs >> 6)); // VrSrc = 0
|
||||
frame.push_byte((velo_ns_abs << 5) | ((v_rate < 0 ? 1 : 0) << 3) | (v_rate_coded_abs >> 6)); // VrSrc = 0
|
||||
frame.push_byte(v_rate_coded_abs << 2);
|
||||
frame.push_byte(0);
|
||||
|
||||
|
||||
@@ -35,7 +35,10 @@ w = numpy.arange(length, dtype=numpy.float64) * (2 * numpy.pi / length)
|
||||
v = numpy.sin(w)
|
||||
print(v)
|
||||
*/
|
||||
constexpr uint16_t sine_table_f32_period = 256;
|
||||
constexpr uint16_t sine_table_f32_period = 256;
|
||||
// periode is 256 . means sine_table_f32[0]= sine_table_f32[0+256], sine_table_f32[1]=sine_table_f32[1+256] (those two added manualy)
|
||||
// Then table has 258 values ,256:[0,..255] + [256] and [257], those two are used when we interpolate[255] with [255+1], and [256] with [256+1]
|
||||
// [256] index is needed in the function sin_f32() when we are inputing very small radian values , example , sin_f32((-1e-14) in radians)
|
||||
|
||||
static constexpr std::array<float, sine_table_f32_period + 2> sine_table_f32{
|
||||
0.00000000e+00, 2.45412285e-02, 4.90676743e-02,
|
||||
@@ -123,7 +126,7 @@ static constexpr std::array<float, sine_table_f32_period + 2> sine_table_f32{
|
||||
-2.42980180e-01, -2.19101240e-01, -1.95090322e-01,
|
||||
-1.70961889e-01, -1.46730474e-01, -1.22410675e-01,
|
||||
-9.80171403e-02, -7.35645636e-02, -4.90676743e-02,
|
||||
-2.45412285e-02, 0.00000000e+00, 0.00000000e+00
|
||||
-2.45412285e-02, 0.00000000e+00, 2.45412285e-02
|
||||
};
|
||||
|
||||
inline float sin_f32(const float w) {
|
||||
|
||||
Reference in New Issue
Block a user