mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-14 04:04:34 +00:00
Merge branch 'next'
This commit is contained in:
commit
cf906684cc
@ -139,6 +139,11 @@ void ReplayAppView::start() {
|
||||
}
|
||||
);
|
||||
}
|
||||
field_rfgain.on_change = [this](int32_t v) {
|
||||
tx_gain = v;
|
||||
};
|
||||
field_rfgain.set_value(tx_gain);
|
||||
receiver_model.set_tx_gain(tx_gain);
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
@ -180,6 +185,8 @@ ReplayAppView::ReplayAppView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
|
||||
tx_gain = 35;field_rfgain.set_value(tx_gain);
|
||||
baseband::run_image(portapack::spi_flash::image_tag_replay);
|
||||
|
||||
add_children({
|
||||
@ -190,7 +197,7 @@ ReplayAppView::ReplayAppView(
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_rfgain,
|
||||
&field_rf_amp,
|
||||
&check_loop,
|
||||
&button_play,
|
||||
|
@ -51,6 +51,7 @@ private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
uint32_t sample_rate = 0;
|
||||
int32_t tx_gain { 47 };
|
||||
static constexpr uint32_t baseband_bandwidth = 2500000;
|
||||
const size_t read_size { 16384 };
|
||||
const size_t buffer_count { 3 };
|
||||
@ -75,7 +76,7 @@ private:
|
||||
bool ready_signal { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
|
||||
{ { 10 * 8, 2 * 16 }, "GAIN A:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Button button_open {
|
||||
@ -103,8 +104,13 @@ private:
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 2 * 16 },
|
||||
};
|
||||
LNAGainField field_lna {
|
||||
{ 14 * 8, 2 * 16 }
|
||||
|
||||
NumberField field_rfgain {
|
||||
{ 14 * 8, 2 * 16 },
|
||||
2,
|
||||
{ 0, 47 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
RFAmpField field_rf_amp {
|
||||
{ 19 * 8, 2 * 16 }
|
||||
|
@ -31,8 +31,9 @@ namespace ui
|
||||
console.writeln("N0vaPixel,klockee,GullCode");
|
||||
console.writeln("jamesshao8,ITAxReal,rascafr");
|
||||
console.writeln("mcules,dqs105,strijar");
|
||||
console.writeln("zhang00963,RedFox-Fr");
|
||||
console.writeln("East2West,fossum");
|
||||
console.writeln("zhang00963,RedFox-Fr,aldude999");
|
||||
console.writeln("East2West,fossum,ArjanOnwezen");
|
||||
console.writeln("vXxOinvizioNxX,teixeluis");
|
||||
console.writeln("");
|
||||
break;
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include "ui_adsb_rx.hpp"
|
||||
#include "ui_alphanum.hpp"
|
||||
|
||||
@ -205,7 +207,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
auto frame = message->frame;
|
||||
uint32_t ICAO_address = frame.get_ICAO_address();
|
||||
|
||||
if (frame.check_CRC() && frame.get_ICAO_address()) {
|
||||
if (frame.check_CRC() && ICAO_address) {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
auto& entry = ::on_packet(recent, ICAO_address);
|
||||
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
|
||||
@ -222,35 +224,51 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
|
||||
uint8_t msg_sub = frame.get_msg_sub();
|
||||
uint8_t * raw_data = frame.get_raw_data();
|
||||
|
||||
if ((msg_type >= 1) && (msg_type <= 4)) {
|
||||
if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) {
|
||||
callsign = decode_frame_id(frame);
|
||||
entry.set_callsign(callsign);
|
||||
logentry+=callsign+" ";
|
||||
} else if (((msg_type >= 9) && (msg_type <= 18)) || ((msg_type >= 20) && (msg_type <= 22))) {
|
||||
}
|
||||
//
|
||||
else if (((msg_type >= AIRBORNE_POS_BARO_L) && (msg_type <= AIRBORNE_POS_BARO_H)) ||
|
||||
((msg_type >= AIRBORNE_POS_GPS_L) && (msg_type <= AIRBORNE_POS_GPS_H))) {
|
||||
entry.set_frame_pos(frame, raw_data[6] & 4);
|
||||
|
||||
if (entry.pos.valid) {
|
||||
str_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
|
||||
" Lat:" + to_string_dec_int(entry.pos.latitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.latitude * 1000) % 100, 2, '0') +
|
||||
" Lon:" + to_string_dec_int(entry.pos.longitude) +
|
||||
"." + to_string_dec_int((int)abs(entry.pos.longitude * 1000) % 100, 2, '0');
|
||||
" Lat:" + to_string_decimal(entry.pos.latitude, 2) +
|
||||
" Lon:" + to_string_decimal(entry.pos.longitude, 2);
|
||||
|
||||
// printing the coordinates in the log file with more
|
||||
// resolution, as we are not constrained by screen
|
||||
// real estate there:
|
||||
|
||||
std::string log_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
|
||||
" Lat:" + to_string_decimal(entry.pos.latitude, 7) +
|
||||
" Lon:" + to_string_decimal(entry.pos.longitude, 7);
|
||||
|
||||
entry.set_info_string(str_info);
|
||||
logentry+=str_info+ " ";
|
||||
logentry+=log_info + " ";
|
||||
|
||||
if (send_updates)
|
||||
// we only want to update the details view if the frame
|
||||
// we received has the same ICAO address, i.e. belongs to
|
||||
// the same aircraft:
|
||||
if(send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
|
||||
details_view->update(entry);
|
||||
}
|
||||
} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
|
||||
}
|
||||
} else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){
|
||||
entry.set_frame_velo(frame);
|
||||
logentry += "Type:" + to_string_dec_uint(msg_sub) +
|
||||
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
|
||||
" Spd: "+ to_string_dec_int(entry.velo.speed);
|
||||
if (send_updates)
|
||||
|
||||
// same here:
|
||||
if (send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
|
||||
details_view->update(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
recent_entries_view.set_dirty();
|
||||
|
||||
logger = std::make_unique<ADSBLogger>();
|
||||
|
@ -40,6 +40,30 @@ namespace ui {
|
||||
#define ADSB_DECAY_B 30
|
||||
#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64
|
||||
|
||||
#define AIRCRAFT_ID_L 1 // aircraft ID message type (lowest type id)
|
||||
#define AIRCRAFT_ID_H 4 // aircraft ID message type (highest type id)
|
||||
|
||||
#define SURFACE_POS_L 5 // surface position (lowest type id)
|
||||
#define SURFACE_POS_H 8 // surface position (highest type id)
|
||||
|
||||
#define AIRBORNE_POS_BARO_L 9 // airborne position (lowest type id)
|
||||
#define AIRBORNE_POS_BARO_H 18 // airborne position (highest type id)
|
||||
|
||||
#define AIRBORNE_VEL 19 // airborne velocities
|
||||
|
||||
#define AIRBORNE_POS_GPS_L 20 // airborne position (lowest type id)
|
||||
#define AIRBORNE_POS_GPS_H 22 // airborne position (highest type id)
|
||||
|
||||
#define RESERVED_L 23 // reserved for other uses
|
||||
#define RESERVED_H 31 // reserved for other uses
|
||||
|
||||
#define VEL_GND_SUBSONIC 1
|
||||
#define VEL_GND_SUPERSONIC 2
|
||||
#define VEL_AIR_SUBSONIC 3
|
||||
#define VEL_AIR_SUPERSONIC 4
|
||||
|
||||
#define O_E_FRAME_TIMEOUT 20 // timeout between odd and even frames
|
||||
|
||||
struct AircraftRecentEntry {
|
||||
using Key = uint32_t;
|
||||
|
||||
@ -49,7 +73,7 @@ struct AircraftRecentEntry {
|
||||
uint16_t hits { 0 };
|
||||
uint32_t age { 0 };
|
||||
adsb_pos pos { false, 0, 0, 0 };
|
||||
adsb_vel velo { false, 0, 999 };
|
||||
adsb_vel velo { false, 0, 999, 0 };
|
||||
ADSBFrame frame_pos_even { };
|
||||
ADSBFrame frame_pos_odd { };
|
||||
|
||||
@ -82,7 +106,7 @@ struct AircraftRecentEntry {
|
||||
frame_pos_odd = frame;
|
||||
|
||||
if (!frame_pos_even.empty() && !frame_pos_odd.empty()) {
|
||||
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < 20)
|
||||
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < O_E_FRAME_TIMEOUT)
|
||||
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
|
||||
}
|
||||
}
|
||||
@ -138,6 +162,8 @@ public:
|
||||
|
||||
std::string title() const override { return "Details"; };
|
||||
|
||||
AircraftRecentEntry get_current_entry() { return entry_copy; }
|
||||
|
||||
private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
|
@ -48,7 +48,7 @@ void RecentEntriesTable<APRSRecentEntries>::draw(
|
||||
) {
|
||||
char aged_color;
|
||||
Color target_color;
|
||||
auto entry_age = entry.age;
|
||||
// auto entry_age = entry.age;
|
||||
|
||||
target_color = Color::green();
|
||||
|
||||
@ -342,7 +342,7 @@ void APRSDetailsView::set_entry(const APRSRecentEntry& entry){
|
||||
|
||||
void APRSDetailsView::update() {
|
||||
if(!hidden()){
|
||||
uint32_t age = entry_copy.age;
|
||||
//uint32_t age = entry_copy.age;
|
||||
|
||||
console.clear(true);
|
||||
console.write(entry_copy.info_string);
|
||||
|
@ -48,6 +48,9 @@ FreqManBaseView::FreqManBaseView(
|
||||
} else
|
||||
error_ = ERROR_NOFILES;
|
||||
|
||||
// initialize
|
||||
change_category(last_category_id);
|
||||
|
||||
// Default function
|
||||
on_change_category = [this](int32_t category_id) {
|
||||
change_category(category_id);
|
||||
|
@ -64,7 +64,7 @@ protected:
|
||||
|
||||
OptionsField options_category {
|
||||
{ 9 * 8, 4 },
|
||||
12,
|
||||
14,
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -103,19 +103,19 @@ private:
|
||||
};
|
||||
|
||||
Labels labels {
|
||||
{ { 2 * 8, 14 * 8 }, "Save as:", Color::white() }
|
||||
{ { 1 * 8, 12 * 8 }, "Save as:", Color::white() }
|
||||
};
|
||||
|
||||
Button button_save_name {
|
||||
{ 2 * 8, 17 * 8, 14 * 8, 48 },
|
||||
{ 1 * 8, 17 * 8, 12 * 8, 48 },
|
||||
"Name (set)"
|
||||
};
|
||||
Button button_save_timestamp {
|
||||
{ 2 * 8, 25 * 8, 14 * 8, 48 },
|
||||
{ 1 * 8, 25 * 8, 12 * 8, 48 },
|
||||
"Timestamp:"
|
||||
};
|
||||
LiveDateTime live_timestamp {
|
||||
{ 17 * 8, 27 * 8, 11 * 8, 16 }
|
||||
{ 14 * 8, 27 * 8, 16 * 8, 16 }
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -285,15 +285,17 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
&checkbox_bloff,
|
||||
&options_bloff,
|
||||
&checkbox_showsplash,
|
||||
&checkbox_showclock,
|
||||
&options_clockformat,
|
||||
&button_ok
|
||||
});
|
||||
|
||||
checkbox_speaker.set_value(persistent_memory::config_speaker());
|
||||
checkbox_showsplash.set_value(persistent_memory::config_splash());
|
||||
checkbox_showclock.set_value(!persistent_memory::hide_clock());
|
||||
//checkbox_login.set_value(persistent_memory::config_login());
|
||||
|
||||
uint32_t backlight_timer = persistent_memory::config_backlight_timer();
|
||||
|
||||
if (backlight_timer) {
|
||||
checkbox_bloff.set_value(true);
|
||||
options_bloff.set_by_value(backlight_timer);
|
||||
@ -301,6 +303,12 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
options_bloff.set_selected_index(0);
|
||||
}
|
||||
|
||||
if (persistent_memory::clock_with_date()) {
|
||||
options_clockformat.set_selected_index(1);
|
||||
} else {
|
||||
options_clockformat.set_selected_index(0);
|
||||
}
|
||||
|
||||
checkbox_speaker.on_select = [this](Checkbox&, bool v) {
|
||||
if (v) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
|
||||
|
||||
@ -316,7 +324,14 @@ SetUIView::SetUIView(NavigationView& nav) {
|
||||
else
|
||||
persistent_memory::set_config_backlight_timer(0);
|
||||
|
||||
if (checkbox_showclock.value()){
|
||||
if (options_clockformat.selected_index() == 1)
|
||||
persistent_memory::set_clock_with_date(true);
|
||||
else
|
||||
persistent_memory::set_clock_with_date(false);
|
||||
}
|
||||
persistent_memory::set_config_splash(checkbox_showsplash.value());
|
||||
persistent_memory::set_clock_hidden(!checkbox_showclock.value());
|
||||
//persistent_memory::set_config_login(checkbox_login.value());
|
||||
nav.pop();
|
||||
};
|
||||
|
@ -51,8 +51,8 @@ public:
|
||||
|
||||
private:
|
||||
Labels labels {
|
||||
{ { 6 * 8, 7 * 16 }, "YYYY/MM/DD HH:MM:SS", Color::grey() },
|
||||
{ { 10 * 8, 9 * 16 }, "/ / : :", Color::light_grey() }
|
||||
{ { 6 * 8, 7 * 16 }, "YYYY-MM-DD HH:MM:SS", Color::grey() },
|
||||
{ { 10 * 8, 9 * 16 }, "- - : :", Color::light_grey() }
|
||||
};
|
||||
|
||||
NumberField field_year {
|
||||
@ -226,19 +226,19 @@ private:
|
||||
};*/
|
||||
|
||||
Checkbox checkbox_speaker {
|
||||
{ 3 * 8, 2 * 16 },
|
||||
{ 3 * 8, 4 * 16 },
|
||||
20,
|
||||
"Hide H1 Speaker option"
|
||||
};
|
||||
|
||||
Checkbox checkbox_bloff {
|
||||
{ 3 * 8, 5 * 16 },
|
||||
{ 3 * 8, 6 * 16 },
|
||||
20,
|
||||
"Backlight off after:"
|
||||
};
|
||||
|
||||
OptionsField options_bloff {
|
||||
{ 52, 6 * 16 + 8 },
|
||||
10,
|
||||
{ 52, 7 * 16 + 8 },
|
||||
20,
|
||||
{
|
||||
{ "5 seconds", 5 },
|
||||
{ "15 seconds", 15 },
|
||||
@ -252,10 +252,25 @@ private:
|
||||
|
||||
Checkbox checkbox_showsplash {
|
||||
{ 3 * 8, 9 * 16 },
|
||||
11,
|
||||
20,
|
||||
"Show splash"
|
||||
};
|
||||
|
||||
Checkbox checkbox_showclock {
|
||||
{ 3 * 8, 11 * 16 },
|
||||
20,
|
||||
"Show clock with:"
|
||||
};
|
||||
|
||||
OptionsField options_clockformat {
|
||||
{ 52, 12 * 16 + 8 },
|
||||
20,
|
||||
{
|
||||
{ "time only", 0 },
|
||||
{ "time and date", 1 }
|
||||
}
|
||||
};
|
||||
|
||||
Button button_ok {
|
||||
{ 2 * 8, 16 * 16, 12 * 8, 32 },
|
||||
"Save"
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "ui_sonde.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
#include <cstring>
|
||||
@ -50,6 +51,8 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&rssi,
|
||||
&field_volume,
|
||||
&check_beep,
|
||||
&check_log,
|
||||
&check_crc,
|
||||
&text_signature,
|
||||
@ -63,6 +66,9 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
&button_see_map
|
||||
});
|
||||
|
||||
// start from the frequency currently stored in the receiver_model:
|
||||
target_frequency_ = receiver_model.tuning_frequency();
|
||||
|
||||
field_frequency.set_value(target_frequency_);
|
||||
field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
@ -80,6 +86,10 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
|
||||
geopos.set_read_only(true);
|
||||
|
||||
check_beep.on_select = [this](Checkbox&, bool v) {
|
||||
beep = v;
|
||||
};
|
||||
|
||||
check_log.on_select = [this](Checkbox&, bool v) {
|
||||
logging = v;
|
||||
};
|
||||
@ -112,11 +122,32 @@ SondeView::SondeView(NavigationView& nav) {
|
||||
if (logger)
|
||||
logger->append(u"sonde.txt");
|
||||
|
||||
// initialize audio:
|
||||
|
||||
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::speaker_unmute();
|
||||
|
||||
// inject a PitchRSSIConfigureMessage in order to arm
|
||||
// the pitch rssi events that will be used by the
|
||||
// processor:
|
||||
const PitchRSSIConfigureMessage message { true, 0 };
|
||||
|
||||
shared_memory.application_queue.push(message);
|
||||
|
||||
baseband::set_pitch_rssi(0, true);
|
||||
}
|
||||
|
||||
SondeView::~SondeView() {
|
||||
baseband::set_pitch_rssi(0, false);
|
||||
radio::disable();
|
||||
baseband::shutdown();
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void SondeView::focus() {
|
||||
@ -156,18 +187,31 @@ void SondeView::on_packet(const sonde::Packet &packet)
|
||||
}
|
||||
|
||||
gps_info = packet.get_GPS_data();
|
||||
|
||||
geopos.set_altitude(gps_info.alt);
|
||||
geopos.set_lat(gps_info.lat);
|
||||
geopos.set_lon(gps_info.lon);
|
||||
|
||||
if (logger && logging)
|
||||
if (logger && logging) {
|
||||
logger->on_packet(packet);
|
||||
}
|
||||
|
||||
if(beep) {
|
||||
baseband::request_beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SondeView::on_headphone_volume_changed(int32_t v) {
|
||||
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
|
||||
receiver_model.set_headphone_volume(new_volume);
|
||||
}
|
||||
|
||||
void SondeView::set_target_frequency(const uint32_t new_value) {
|
||||
target_frequency_ = new_value;
|
||||
radio::set_tuning_frequency(tuning_frequency());
|
||||
//radio::set_tuning_frequency(tuning_frequency());
|
||||
// we better remember the tuned frequency, by using this function instead:
|
||||
receiver_model.set_tuning_frequency(target_frequency_);
|
||||
}
|
||||
|
||||
uint32_t SondeView::tuning_frequency() const {
|
||||
|
@ -68,10 +68,14 @@ private:
|
||||
uint32_t target_frequency_ { 402700000 };
|
||||
bool logging { false };
|
||||
bool use_crc { false };
|
||||
bool beep { false };
|
||||
|
||||
sonde::GPS_data gps_info { };
|
||||
sonde::temp_humid temp_humid_info { };
|
||||
std::string sonde_id { };
|
||||
|
||||
// AudioOutput audio_output { };
|
||||
|
||||
Labels labels {
|
||||
{ { 4 * 8, 2 * 16 }, "Type:", Color::light_grey() },
|
||||
{ { 6 * 8, 3 * 16 }, "ID:", Color::light_grey() },
|
||||
@ -103,14 +107,29 @@ private:
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
|
||||
NumberField field_volume {
|
||||
{ 28 * 8, 0 * 16 },
|
||||
2,
|
||||
{ 0, 99 },
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
|
||||
Checkbox check_beep {
|
||||
{ 22 * 8, 6 * 16 },
|
||||
3,
|
||||
"Beep"
|
||||
};
|
||||
|
||||
Checkbox check_log {
|
||||
{ 23 * 8, 6 * 16 },
|
||||
{ 22 * 8, 8 * 16 },
|
||||
3,
|
||||
"Log"
|
||||
};
|
||||
|
||||
Checkbox check_crc {
|
||||
{ 23 * 8, 8 * 16 },
|
||||
{ 22 * 8, 10 * 16 },
|
||||
3,
|
||||
"CRC"
|
||||
};
|
||||
@ -170,7 +189,10 @@ private:
|
||||
};
|
||||
|
||||
void on_packet(const sonde::Packet& packet);
|
||||
void on_headphone_volume_changed(int32_t v);
|
||||
|
||||
void set_target_frequency(const uint32_t new_value);
|
||||
|
||||
uint32_t tuning_frequency() const;
|
||||
};
|
||||
|
||||
|
@ -141,6 +141,9 @@ Continuous (Fox-oring)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "rffc507x.hpp" /* c/m, avoiding initial short ON Ant_DC_Bias pulse, from cold reset */
|
||||
rffc507x::RFFC507x first_if;
|
||||
|
||||
static void event_loop() {
|
||||
ui::Context context;
|
||||
ui::SystemView system_view {
|
||||
@ -160,6 +163,7 @@ static void event_loop() {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
|
||||
if( portapack::init() ) {
|
||||
portapack::display.init();
|
||||
|
||||
|
@ -83,7 +83,7 @@ TransmitterModel transmitter_model;
|
||||
TemperatureLogger temperature_logger;
|
||||
|
||||
bool antenna_bias { false };
|
||||
uint8_t bl_tick_counter { 0 };
|
||||
uint32_t bl_tick_counter { 0 };
|
||||
|
||||
void set_antenna_bias(const bool v) {
|
||||
antenna_bias = v;
|
||||
|
@ -54,7 +54,7 @@ extern TransmitterModel transmitter_model;
|
||||
extern bool speaker_mode;
|
||||
void set_speaker_mode(const bool v);
|
||||
|
||||
extern uint8_t bl_tick_counter;
|
||||
extern uint32_t bl_tick_counter;
|
||||
extern bool antenna_bias;
|
||||
|
||||
extern TemperatureLogger temperature_logger;
|
||||
|
@ -111,14 +111,12 @@ void set_direction(const rf::Direction new_direction) {
|
||||
// Hack to fix the CPLD (clocking ?) bug: toggle CPLD SRAM overlay depending on new direction
|
||||
// Use CPLD's EEPROM config when transmitting
|
||||
// Use the SRAM overlay when receiving
|
||||
if (direction != new_direction) {
|
||||
if (new_direction == rf::Direction::Transmit) {
|
||||
|
||||
// teixeluis: undone "Hack to fix the CPLD (clocking ?) bug".
|
||||
// Apparently with current CPLD code from the hackrf repo,
|
||||
// toggling CPLD overlay should no longer be necessary:
|
||||
if (direction != new_direction && new_direction == rf::Direction::Transmit) {
|
||||
hackrf::cpld::init_from_eeprom();
|
||||
} else {
|
||||
if( !hackrf::cpld::load_sram() ) {
|
||||
chSysHalt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
direction = new_direction;
|
||||
|
@ -171,7 +171,11 @@ void ReceiverModel::enable() {
|
||||
update_baseband_bandwidth();
|
||||
update_sampling_rate();
|
||||
update_modulation();
|
||||
|
||||
// TODO: would challenge if this should belong to the
|
||||
// receiver_model namespace:
|
||||
update_headphone_volume();
|
||||
|
||||
led_rx.on();
|
||||
}
|
||||
|
||||
@ -182,6 +186,10 @@ void ReceiverModel::disable() {
|
||||
// TODO: Responsibility for enabling/disabling the radio is muddy.
|
||||
// Some happens in ReceiverModel, some inside radio namespace.
|
||||
radio::disable();
|
||||
|
||||
// TODO: we are doing this repeatedly in different levels of the
|
||||
// call stack. Keeping it for now, but there seem to be too many
|
||||
// redundant calls:
|
||||
led_rx.off();
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,23 @@ std::string to_string_dec_int(
|
||||
return q;
|
||||
}
|
||||
|
||||
std::string to_string_decimal(float decimal, int8_t precision) {
|
||||
double integer_part;
|
||||
double fractional_part;
|
||||
|
||||
std::string result;
|
||||
|
||||
fractional_part = modf(decimal, &integer_part) * pow(10, precision);
|
||||
|
||||
if (fractional_part < 0) {
|
||||
fractional_part = -fractional_part;
|
||||
}
|
||||
|
||||
result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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');
|
||||
return final_str;
|
||||
@ -165,8 +182,8 @@ std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format) {
|
||||
std::string string { "" };
|
||||
|
||||
if (format == YMDHMS) {
|
||||
string += to_string_dec_uint(value.year(), 4) + "/" +
|
||||
to_string_dec_uint(value.month(), 2, '0') + "/" +
|
||||
string += to_string_dec_uint(value.year(), 4) + "-" +
|
||||
to_string_dec_uint(value.month(), 2, '0') + "-" +
|
||||
to_string_dec_uint(value.day(), 2, '0') + " ";
|
||||
}
|
||||
|
||||
@ -189,11 +206,11 @@ std::string to_string_timestamp(const rtc::RTC& value) {
|
||||
}
|
||||
|
||||
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp) {
|
||||
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "/" +
|
||||
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2) + "/" +
|
||||
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2) + " " +
|
||||
to_string_dec_uint((timestamp.FAT_time >> 11), 2) + ":" +
|
||||
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2);
|
||||
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "-" +
|
||||
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2, '0') + "-" +
|
||||
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2, '0') + " " +
|
||||
to_string_dec_uint((timestamp.FAT_time >> 11), 2, '0') + ":" +
|
||||
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2, '0');
|
||||
}
|
||||
|
||||
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision) {
|
||||
|
@ -43,6 +43,8 @@ const char unit_prefix[7] { 'n', 'u', 'm', 0, 'k', 'M', 'G' };
|
||||
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
|
||||
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = ' ');
|
||||
std::string to_string_dec_int(const int32_t n, const int32_t l = 0, const char fill = 0);
|
||||
std::string to_string_decimal(float decimal, int8_t precision);
|
||||
|
||||
std::string to_string_hex(const uint64_t n, const int32_t l = 0);
|
||||
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
|
||||
|
||||
|
@ -63,17 +63,9 @@ GeoPos::GeoPos(
|
||||
const auto changed_fn = [this](int32_t) {
|
||||
float lat_value = lat();
|
||||
float lon_value = lon();
|
||||
double integer_part;
|
||||
double fractional_part;
|
||||
|
||||
fractional_part = modf(lat_value, &integer_part) * 100000;
|
||||
if (fractional_part < 0)
|
||||
fractional_part = -fractional_part;
|
||||
text_lat_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
|
||||
fractional_part = modf(lon_value, &integer_part) * 100000;
|
||||
if (fractional_part < 0)
|
||||
fractional_part = -fractional_part;
|
||||
text_lon_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
|
||||
text_lat_decimal.set(to_string_decimal(lat_value, 5));
|
||||
text_lon_decimal.set(to_string_decimal(lon_value, 5));
|
||||
|
||||
if (on_change && report_change)
|
||||
on_change(altitude(), lat_value, lon_value);
|
||||
|
@ -75,9 +75,10 @@ void RSSI::paint(Painter& painter) {
|
||||
Color::black()
|
||||
);
|
||||
|
||||
if (pitch_rssi_enabled)
|
||||
if (pitch_rssi_enabled) {
|
||||
baseband::set_pitch_rssi((avg_ - raw_min) * 2000 / raw_delta, true);
|
||||
}
|
||||
}
|
||||
|
||||
void RSSI::set_pitch_rssi(bool enabled) {
|
||||
pitch_rssi_enabled = enabled;
|
||||
|
@ -103,6 +103,7 @@ void TransmitterView::set_transmitting(const bool transmitting) {
|
||||
|
||||
void TransmitterView::on_show() {
|
||||
field_frequency.set_value(transmitter_model.tuning_frequency());
|
||||
field_frequency_step.set_by_value(receiver_model.frequency_step());
|
||||
|
||||
field_gain.set_value(transmitter_model.tx_gain());
|
||||
field_amp.set_value(transmitter_model.rf_amp() ? 14 : 0);
|
||||
@ -122,6 +123,7 @@ TransmitterView::TransmitterView(
|
||||
|
||||
add_children({
|
||||
&field_frequency,
|
||||
&field_frequency_step,
|
||||
&text_gain,
|
||||
&field_gain,
|
||||
&button_start,
|
||||
@ -158,6 +160,10 @@ TransmitterView::TransmitterView(
|
||||
on_edit_frequency();
|
||||
};
|
||||
|
||||
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->field_frequency.set_step(v);
|
||||
};
|
||||
|
||||
field_gain.on_change = [this](uint32_t tx_gain) {
|
||||
on_tx_gain_changed(tx_gain);
|
||||
};
|
||||
|
@ -124,11 +124,11 @@ private:
|
||||
};
|
||||
|
||||
Text text_bw {
|
||||
{ 11 * 8, 1 * 8, 9 * 8, 1 * 16 },
|
||||
"BW: kHz"
|
||||
{ 18 * 8, 1 * 8, 3 * 8, 1 * 16 },
|
||||
"kHz"
|
||||
};
|
||||
NumberField field_bw {
|
||||
{ 14 * 8, 1 * 8 },
|
||||
{ 15 * 8, 1 * 8 },
|
||||
3,
|
||||
{ 1, 150 },
|
||||
1,
|
||||
@ -153,6 +153,10 @@ private:
|
||||
"START"
|
||||
};
|
||||
|
||||
FrequencyStepView field_frequency_step {
|
||||
{ 10 * 8 - 4, 1 * 8 },
|
||||
};
|
||||
|
||||
void on_tuning_frequency_changed(rf::Frequency f);
|
||||
void on_channel_bandwidth_changed(uint32_t channel_bandwidth);
|
||||
void on_tx_gain_changed(int32_t tx_gain);
|
||||
|
@ -68,7 +68,7 @@
|
||||
#include "ui_view_wav.hpp"
|
||||
#include "ui_whipcalc.hpp"
|
||||
|
||||
#include "acars_app.hpp"
|
||||
//#include "acars_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "analog_tv_app.hpp"
|
||||
@ -350,13 +350,21 @@ InformationView::InformationView(
|
||||
});
|
||||
|
||||
version.set_style(&style_infobar);
|
||||
|
||||
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
|
||||
ltime.set_style(&style_infobar);
|
||||
ltime.set_seconds_enabled(true);
|
||||
ltime.set_date_enabled(false);
|
||||
|
||||
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void InformationView::refresh() {
|
||||
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
|
||||
ltime.set_seconds_enabled(true);
|
||||
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
|
||||
|
||||
}
|
||||
|
||||
/* Navigation ************************************************************/
|
||||
|
||||
bool NavigationView::is_top() const {
|
||||
@ -387,6 +395,7 @@ void NavigationView::pop() {
|
||||
|
||||
update_view();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NavigationView::pop_modal() {
|
||||
@ -606,6 +615,7 @@ SystemView::SystemView(
|
||||
}
|
||||
else{
|
||||
add_child(&info_view);
|
||||
info_view.refresh();
|
||||
}
|
||||
|
||||
this->status_view.set_back_enabled(!this->navigation_view.is_top());
|
||||
|
@ -212,7 +212,7 @@ private:
|
||||
class InformationView : public View {
|
||||
public:
|
||||
InformationView(NavigationView& nav);
|
||||
|
||||
void refresh();
|
||||
private:
|
||||
static constexpr auto version_string = "v1.4.0";
|
||||
NavigationView& nav_;
|
||||
@ -228,8 +228,10 @@ private:
|
||||
};
|
||||
|
||||
LiveDateTime ltime {
|
||||
{174, 0, 8 * 8, 16}
|
||||
{86, 0, 19 * 8, 16}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
class BMPView : public View {
|
||||
|
@ -114,7 +114,7 @@ AM::AM() {
|
||||
|
||||
void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
|
||||
int32_t sample = 0;
|
||||
int8_t re, im;
|
||||
int8_t re = 0, im = 0;
|
||||
float q = 0.0;
|
||||
|
||||
for (size_t counter = 0; counter < buffer.count; counter++) {
|
||||
@ -125,8 +125,8 @@ void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
|
||||
q = sample / 32768.0f;
|
||||
q *= 64.0f;
|
||||
switch (mode) {
|
||||
case Mode::AM: re = q + 20; im = q + 20;
|
||||
case Mode::DSB: re = q; im = q;
|
||||
case Mode::AM: re = q + 20; im = q + 20; break;
|
||||
case Mode::DSB: re = q; im = q; break;
|
||||
default: break;
|
||||
}
|
||||
buffer.p[counter] = { re, im };
|
||||
|
@ -141,8 +141,7 @@ bool APRSRxProcessor::parse_bit(const uint8_t current_bit){
|
||||
uint8_t decoded_bit = ~(current_bit ^ last_bit) & 0x1;
|
||||
last_bit = current_bit;
|
||||
|
||||
int16_t log = decoded_bit == 0 ? -32768 : 32767;
|
||||
|
||||
//int16_t log = decoded_bit == 0 ? -32768 : 32767;
|
||||
//if(stream){
|
||||
// const size_t bytes_to_write = sizeof(log) * 1;
|
||||
// const auto result = stream->write(&log, bytes_to_write);
|
||||
|
@ -26,9 +26,16 @@
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include "audio_output.hpp"
|
||||
|
||||
SondeProcessor::SondeProcessor() {
|
||||
|
||||
decim_0.configure(taps_11k0_decim_0.taps, 33554432);
|
||||
decim_1.configure(taps_11k0_decim_1.taps, 131072);
|
||||
|
||||
audio_output.configure(false);
|
||||
|
||||
tone_gen.configure(BEEP_BASE_FREQ, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
|
||||
}
|
||||
|
||||
void SondeProcessor::execute(const buffer_c8_t& buffer) {
|
||||
@ -47,10 +54,97 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) {
|
||||
clock_recovery_fsk_4800(mf.get_output());
|
||||
}
|
||||
}
|
||||
|
||||
if(pitch_rssi_enabled) {
|
||||
if(beep_play) {
|
||||
// if we let the buffer underrun, for some reason
|
||||
// once it starts looping it ignores zero (silence)
|
||||
// samples, so we need to keep feeding the buffer
|
||||
// and not be able to take advantage of the circular
|
||||
// buffer loop:
|
||||
//beep_play = false;
|
||||
generate_beep();
|
||||
}
|
||||
|
||||
if(silence_play) {
|
||||
//silence_play = false;
|
||||
generate_silence();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SondeProcessor::on_message(const Message* const msg) {
|
||||
switch(msg->id) {
|
||||
case Message::ID::RequestSignal:
|
||||
if ((*reinterpret_cast<const RequestSignalMessage*>(msg)).signal == RequestSignalMessage::Signal::BeepRequest) {
|
||||
float rssi_ratio = (float) last_rssi / (float) RSSI_CEILING;
|
||||
int beep_duration = 0;
|
||||
|
||||
if(rssi_ratio <= PROPORTIONAL_BEEP_THRES) {
|
||||
beep_duration = BEEP_MIN_DURATION;
|
||||
}
|
||||
else if(rssi_ratio < 1) {
|
||||
beep_duration = (int) rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
|
||||
}
|
||||
else {
|
||||
beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
|
||||
}
|
||||
|
||||
play_beep();
|
||||
chThdSleepMilliseconds(beep_duration);
|
||||
stop_beep();
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::ID::PitchRSSIConfigure:
|
||||
pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(msg));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SondeProcessor::play_beep() {
|
||||
beep_play = true;
|
||||
silence_play = false;
|
||||
}
|
||||
|
||||
void SondeProcessor::stop_beep() {
|
||||
beep_play = false;
|
||||
silence_play = true;
|
||||
}
|
||||
|
||||
void SondeProcessor::generate_beep() {
|
||||
// here we let the samples be created using the ToneGen class:
|
||||
|
||||
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
|
||||
audio_buffer.p[i] = (int16_t) ((tone_gen.process(0) >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
audio_output.write(audio_buffer);
|
||||
}
|
||||
|
||||
void SondeProcessor::generate_silence() {
|
||||
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
|
||||
audio_buffer.p[i] = 0;
|
||||
}
|
||||
|
||||
audio_output.write(audio_buffer);
|
||||
}
|
||||
|
||||
void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
|
||||
pitch_rssi_enabled = message.enabled;
|
||||
|
||||
uint32_t freq = (int) ((float) message.rssi * (float) RSSI_PITCH_WEIGHT + (float) BEEP_BASE_FREQ);
|
||||
|
||||
last_rssi = message.rssi;
|
||||
tone_gen.configure(freq, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher { std::make_unique<SondeProcessor>() };
|
||||
event_dispatcher.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -88,19 +88,51 @@
|
||||
#include "message.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "audio_output.hpp"
|
||||
#include "tone_gen.hpp"
|
||||
|
||||
#include "buffer.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <bitset>
|
||||
|
||||
|
||||
#define BEEP_MIN_DURATION 60
|
||||
#define BEEP_DURATION_RANGE 100
|
||||
#define BEEP_BASE_FREQ 200
|
||||
#define RSSI_CEILING 1000
|
||||
#define PROPORTIONAL_BEEP_THRES 0.8
|
||||
#define RSSI_PITCH_WEIGHT 0.5
|
||||
#define AUDIO_SAMPLE_RATE 24000
|
||||
|
||||
class SondeProcessor : public BasebandProcessor {
|
||||
public:
|
||||
SondeProcessor();
|
||||
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
|
||||
void on_message(const Message* const msg);
|
||||
private:
|
||||
|
||||
static constexpr size_t baseband_fs = 2457600;
|
||||
|
||||
std::array<int16_t, 32> audio { };
|
||||
|
||||
const buffer_s16_t audio_buffer {
|
||||
(int16_t*) audio.data(),
|
||||
sizeof(audio) / sizeof(int16_t)
|
||||
};
|
||||
|
||||
AudioOutput audio_output { };
|
||||
|
||||
bool beep_play { false };
|
||||
bool silence_play { false };
|
||||
bool pitch_rssi_enabled { false };
|
||||
|
||||
uint32_t last_rssi { 0 };
|
||||
|
||||
ToneGen tone_gen { };
|
||||
|
||||
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
|
||||
RSSIThread rssi_thread { NORMALPRIO + 10 };
|
||||
|
||||
@ -149,6 +181,23 @@ private:
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
};
|
||||
|
||||
void play_beep();
|
||||
void stop_beep();
|
||||
|
||||
/**
|
||||
* Used for filling the audio buffer with the waveform
|
||||
* generated by the ToneGen class:
|
||||
*
|
||||
*/
|
||||
void generate_beep();
|
||||
|
||||
/**
|
||||
* Used for filling the audio buffer with silence:
|
||||
*/
|
||||
void generate_silence();
|
||||
|
||||
void pitch_rssi_config(const PitchRSSIConfigureMessage& message);
|
||||
};
|
||||
|
||||
#endif/*__PROC_ERT_H__*/
|
||||
|
@ -23,18 +23,56 @@
|
||||
#include "tone_gen.hpp"
|
||||
#include "sine_table_int8.hpp"
|
||||
|
||||
|
||||
int32_t ToneGen::tone_sine() {
|
||||
int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000;
|
||||
tone_phase_ += delta_;
|
||||
|
||||
return tone_sample;
|
||||
}
|
||||
|
||||
int32_t ToneGen::tone_square() {
|
||||
int32_t tone_sample = 0;
|
||||
|
||||
if(tone_phase_ < (UINT32_MAX / 2)) {
|
||||
tone_sample = INT32_MAX;
|
||||
}
|
||||
else {
|
||||
tone_sample = INT32_MIN;
|
||||
}
|
||||
|
||||
tone_phase_ += delta_;
|
||||
|
||||
return tone_sample;
|
||||
}
|
||||
|
||||
void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) {
|
||||
delta_ = delta;
|
||||
delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24);
|
||||
tone_mix_weight_ = tone_mix_weight;
|
||||
input_mix_weight_ = 1.0 - tone_mix_weight;
|
||||
|
||||
current_tone_type_ = sine;
|
||||
}
|
||||
|
||||
void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) {
|
||||
delta_ = (uint8_t) ((freq * sizeof(sine_table_i8)) / sample_rate);
|
||||
tone_mix_weight_ = tone_mix_weight;
|
||||
input_mix_weight_ = 1.0 - tone_mix_weight;
|
||||
current_tone_type_ = tone_type;
|
||||
}
|
||||
|
||||
int32_t ToneGen::process(const int32_t sample_in) {
|
||||
if (!delta_)
|
||||
return sample_in;
|
||||
|
||||
int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24];
|
||||
tone_phase_ += delta_;
|
||||
int32_t tone_sample = 0;
|
||||
|
||||
if(current_tone_type_ == sine) {
|
||||
tone_sample = tone_sine();
|
||||
}
|
||||
else if(current_tone_type_ == square) {
|
||||
tone_sample = tone_square();
|
||||
}
|
||||
|
||||
return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_);
|
||||
}
|
||||
|
@ -28,19 +28,36 @@
|
||||
|
||||
class ToneGen {
|
||||
public:
|
||||
enum tone_type { sine, square };
|
||||
|
||||
/*ToneGen(const size_t sample_rate
|
||||
) : sample_rate_ { sample_rate }
|
||||
{};*/
|
||||
|
||||
void configure(const uint32_t delta, const float tone_mix_weight);
|
||||
void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate);
|
||||
|
||||
int32_t process(const int32_t sample_in);
|
||||
|
||||
private:
|
||||
//size_t sample_rate_;
|
||||
tone_type current_tone_type_ { sine };
|
||||
|
||||
float input_mix_weight_ { 1 };
|
||||
float tone_mix_weight_ { 0 };
|
||||
uint32_t delta_ { 0 };
|
||||
uint32_t tone_phase_ { 0 };
|
||||
|
||||
uint8_t delta_ { 0 };
|
||||
uint8_t tone_phase_ { 0 };
|
||||
|
||||
/**
|
||||
* Generator function which selects every other sample from the reference sine waveform to the output sample:
|
||||
*/
|
||||
int32_t tone_sine();
|
||||
|
||||
|
||||
/**
|
||||
* Generator function for square waves:
|
||||
*/
|
||||
int32_t tone_square();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* __TONE_GEN_H__ */
|
||||
|
@ -141,7 +141,11 @@ float cpr_mod(float a, float b) {
|
||||
return a - (b * floor(a / b));
|
||||
}
|
||||
|
||||
int cpr_NL(float lat) {
|
||||
int cpr_NL_precise(float lat) {
|
||||
return (int) floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
|
||||
}
|
||||
|
||||
int cpr_NL_approx(float lat) {
|
||||
if (lat < 0)
|
||||
lat = -lat; // Symmetry
|
||||
|
||||
@ -153,6 +157,18 @@ int cpr_NL(float lat) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cpr_NL(float lat) {
|
||||
// TODO prove that the approximate function is good
|
||||
// enough for the precision we need. Uncomment if
|
||||
// that is true. No performance penalty was noticed
|
||||
// from testing, but if you find it might be an issue,
|
||||
// switch to cpr_NL_approx() instead:
|
||||
|
||||
//return cpr_NL_approx(lat);
|
||||
|
||||
return cpr_NL_precise(lat);
|
||||
}
|
||||
|
||||
int cpr_N(float lat, int is_odd) {
|
||||
int nl = cpr_NL(lat) - is_odd;
|
||||
|
||||
@ -185,18 +201,18 @@ void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32
|
||||
// CPR encoding
|
||||
// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
|
||||
|
||||
delta_lat = 360.0 / ((4.0 * 15.0) - time_parity); // NZ = 15
|
||||
yz = floor(131072.0 * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
|
||||
rlat = delta_lat * ((yz / 131072.0) + floor(latitude / delta_lat));
|
||||
delta_lat = 360.0 / ((4.0 * NZ) - time_parity); // NZ = 15
|
||||
yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
|
||||
rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
|
||||
|
||||
if ((cpr_NL(rlat) - time_parity) > 0)
|
||||
delta_lon = 360.0 / cpr_N(rlat, time_parity);
|
||||
else
|
||||
delta_lon = 360.0;
|
||||
xz = floor(131072.0 * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
|
||||
xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
|
||||
|
||||
lat = cpr_mod(yz, 131072.0);
|
||||
lon = cpr_mod(xz, 131072.0);
|
||||
lat = cpr_mod(yz, CPR_MAX_VALUE);
|
||||
lon = cpr_mod(xz, CPR_MAX_VALUE);
|
||||
|
||||
frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15)); // T = 0
|
||||
frame.push_byte(lat >> 7);
|
||||
@ -258,7 +274,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
|
||||
// Compute longitude
|
||||
if (time_even > time_odd) {
|
||||
// Use even frame
|
||||
// Use even frame2
|
||||
ni = cpr_N(latE, 0);
|
||||
Dlon = 360.0 / ni;
|
||||
|
||||
@ -279,7 +295,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
|
||||
position.latitude = latO;
|
||||
}
|
||||
|
||||
if (position.longitude > 180) position.longitude -= 360;
|
||||
if (position.longitude >= 180) position.longitude -= 360;
|
||||
|
||||
position.valid = true;
|
||||
|
||||
|
@ -83,6 +83,10 @@ const float adsb_lat_lut[58] = {
|
||||
86.53536998, 87.00000000
|
||||
};
|
||||
|
||||
const float PI = 3.14159265358979323846;
|
||||
|
||||
const float NZ = 15.0;
|
||||
|
||||
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address);
|
||||
|
||||
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign);
|
||||
|
@ -339,9 +339,9 @@ private:
|
||||
std::string lat_str = "";
|
||||
std::string lng_str = "";
|
||||
|
||||
bool is_north;
|
||||
bool is_west;
|
||||
uint8_t lng_offset;
|
||||
bool is_north = false;
|
||||
bool is_west = false;
|
||||
uint8_t lng_offset = 0;
|
||||
for(uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++){
|
||||
uint8_t ascii = payload[i] >> 1;
|
||||
|
||||
|
@ -224,9 +224,17 @@ void set_playdead_sequence(const uint32_t new_value) {
|
||||
|
||||
// ui_config is an uint32_t var storing information bitwise
|
||||
// bits 0,1,2 store the backlight timer
|
||||
// bits 31, 30,29,28,27 stores the different single bit configs depicted below
|
||||
// bits 31, 30,29,28,27, 26, 25 stores the different single bit configs depicted below
|
||||
// bits on position 4 to 19 (16 bits) store the clkout frequency
|
||||
|
||||
bool hide_clock() { // clock hidden from main menu
|
||||
return data->ui_config & (1 << 25);
|
||||
}
|
||||
|
||||
bool clock_with_date() { // show clock with date, if not hidden
|
||||
return data->ui_config & (1 << 26);
|
||||
}
|
||||
|
||||
bool clkout_enabled() {
|
||||
return data->ui_config & (1 << 27);
|
||||
}
|
||||
@ -251,6 +259,14 @@ uint32_t config_backlight_timer() {
|
||||
return timer_seconds[data->ui_config & 7]; //first three bits, 8 possible values
|
||||
}
|
||||
|
||||
void set_clock_hidden(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 25)) | (v << 25);
|
||||
}
|
||||
|
||||
void set_clock_with_date(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 26)) | (v << 26);
|
||||
}
|
||||
|
||||
void set_clkout_enabled(bool v) {
|
||||
data->ui_config = (data->ui_config & ~(1 << 27)) | (v << 27);
|
||||
}
|
||||
|
@ -75,11 +75,15 @@ bool stealth_mode();
|
||||
void set_stealth_mode(const bool v);
|
||||
|
||||
bool config_splash();
|
||||
bool hide_clock();
|
||||
bool clock_with_date();
|
||||
bool config_login();
|
||||
bool config_speaker();
|
||||
uint32_t config_backlight_timer();
|
||||
|
||||
void set_config_splash(bool v);
|
||||
void set_clock_hidden(bool v);
|
||||
void set_clock_with_date(bool v);
|
||||
void set_config_login(bool v);
|
||||
void set_config_speaker(bool v);
|
||||
void set_config_backlight_timer(uint32_t i);
|
||||
|
@ -44,4 +44,5 @@ static const int8_t sine_table_i8[256] = {
|
||||
-49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -13, -9, -6, -3
|
||||
};
|
||||
|
||||
|
||||
#endif/*__SINE_TABLE_I8_H__*/
|
||||
|
@ -410,9 +410,14 @@ void Labels::paint(Painter& painter) {
|
||||
void LiveDateTime::on_tick_second() {
|
||||
rtcGetTime(&RTCD1, &datetime);
|
||||
text = "";
|
||||
|
||||
if(!hide_clock) {
|
||||
if(date_enabled){
|
||||
text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " ";
|
||||
text = to_string_dec_uint(datetime.year(), 4, '0') + "-" +
|
||||
to_string_dec_uint(datetime.month(), 2, '0') + "-" +
|
||||
to_string_dec_uint(datetime.day(), 2, '0') + " ";
|
||||
}
|
||||
else{
|
||||
text = " ";
|
||||
}
|
||||
|
||||
text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0');
|
||||
@ -429,6 +434,7 @@ void LiveDateTime::on_tick_second() {
|
||||
init_delay--;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
@ -459,6 +465,9 @@ void LiveDateTime::paint(Painter& painter) {
|
||||
text
|
||||
);
|
||||
}
|
||||
void LiveDateTime::set_hide_clock(bool new_value){
|
||||
this->hide_clock = new_value;
|
||||
}
|
||||
|
||||
void LiveDateTime::set_date_enabled(bool new_value){
|
||||
this->date_enabled = new_value;
|
||||
|
@ -244,6 +244,7 @@ public:
|
||||
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
void set_hide_clock(bool new_value);
|
||||
void set_seconds_enabled(bool new_value);
|
||||
void set_date_enabled(bool new_value);
|
||||
|
||||
@ -255,6 +256,7 @@ private:
|
||||
void on_tick_second();
|
||||
|
||||
uint16_t init_delay = 4;
|
||||
bool hide_clock = false;
|
||||
bool date_enabled = true;
|
||||
bool seconds_enabled = false;
|
||||
|
||||
|
46
sdcard/FREQMAN/GSM-NL.TXT
Normal file
46
sdcard/FREQMAN/GSM-NL.TXT
Normal file
@ -0,0 +1,46 @@
|
||||
a=703000000,b=713000000,d=5G 700u Vodafone
|
||||
a=713000000,b=723000000,d=5G 700u KPN
|
||||
a=723000000,b=733000000,d=5G 700u T-Mobile
|
||||
a=758000000,b=768000000,d=5G 700d Vodafone
|
||||
a=768000000,b=778000000,d=5G 700d KPN
|
||||
a=778000000,b=788000000,d=5G 700d T-Mobile
|
||||
a=791000000,b=801000000,d=4G 800d T-Mobile
|
||||
a=801000000,b=811000000,d=4G 800d Vodafone
|
||||
a=811000000,b=821000000,d=4G 800d KPN
|
||||
a=832000000,b=842000000,d=4G 800u T-Mobile
|
||||
a=842000000,b=852000000,d=4G 800u Vodafone
|
||||
a=852000000,b=862000000,d=4G 800u KPN
|
||||
a=880000000,b=890000000,d=2G_3G 900u Vodafone
|
||||
a=890000000,b=900000000,d=2G_3G 900u KPN
|
||||
a=900000000,b=915000000,d=4G 900u T-Mobile
|
||||
a=925000000,b=935000000,d=2G_3G 900d Vodafone
|
||||
a=935000000,b=945000000,d=2G_3G 900d KPN
|
||||
a=945000000,b=960000000,d=4G 900d T-Mobile
|
||||
a=1452000000,b=1467000000,d=2G_3G 1400d Vodafone
|
||||
a=1467000000,b=1482000000,d=2G_3G 1400d KPN
|
||||
a=1482000000,b=1492000000,d=4G 1400d T-Mobile
|
||||
a=1710000000,b=1730000000,d=4G 1800u KPN
|
||||
a=1730000000,b=1750000000,d=4G 1800u Vodafone
|
||||
a=1750000000,b=1780000000,d=4G 1800u T-Mobile
|
||||
a=1805000000,b=1825000000,d=4G 1800d KPN
|
||||
a=1825000000,b=1845000000,d=4G 1800d Vodafone
|
||||
a=1845000000,b=1875000000,d=4G 1800d T-Mobile
|
||||
a=1920000000,b=1940000000,d=3G_4G 2100u Vodafone
|
||||
a=1940000000,b=1960000000,d=3G_4G 2100u T-Mobile
|
||||
a=1960000000,b=1980000000,d=3G_4G 2100u KPN
|
||||
a=2110000000,b=2130000000,d=3G_4G 2100d Vodafone
|
||||
a=2130000000,b=2150000000,d=3G_4G 2100d T-Mobile
|
||||
a=2150000000,b=2170000000,d=3G_4G 2100d KPN
|
||||
a=2500000000,b=2510000000,d=LTE 2600u Vodafone
|
||||
a=2510000000,b=2530000000,d=LTE 2600u Vodafone
|
||||
a=2530000000,b=2535000000,d=LTE 2600u T-Mobile
|
||||
a=2535000000,b=2545000000,d=LTE 2600u KPN
|
||||
a=2545000000,b=2565000000,d=LTE 2600u T-Mobile
|
||||
a=2565000000,b=2590000000,d=4G 2600d_u T-Mobile
|
||||
a=2590000000,b=2620000000,d=4G 2600d_u KPN
|
||||
a=2620000000,b=2630000000,d=LTE 2600d Vodafone
|
||||
a=2630000000,b=2650000000,d=LTE 2600d Vodafone
|
||||
a=2650000000,b=2655000000,d=LTE 2600d T-Mobile
|
||||
a=2655000000,b=2665000000,d=LTE 2600d KPN
|
||||
a=2665000000,b=2685000000,d=LTE 2600d T-Mobile
|
||||
a=2685000000,b=2690000000,d=UNKNOWNd_u 2600 T-Mobile
|
7
sdcard/FREQMAN/ISM.TXT
Normal file
7
sdcard/FREQMAN/ISM.TXT
Normal file
@ -0,0 +1,7 @@
|
||||
f=13560000,d=Worldwide 13.56 MHz
|
||||
f=27120000,d=Worldwide 27MHz
|
||||
f=40660000,d=Worldwide 40MHz
|
||||
f=433920000,d=ITU Reg 1 433 MHz
|
||||
f=915000000,d=ITU Reg 2 915 MHz
|
||||
f=2450000000,d=Worldwide 2.4 GHz
|
||||
f=5800000000,d=Worldwide 5.8 GHz
|
46
sdcard/FREQMAN/RADIOSONDE.TXT
Normal file
46
sdcard/FREQMAN/RADIOSONDE.TXT
Normal file
@ -0,0 +1,46 @@
|
||||
f=400500000,d=AU SE
|
||||
f=401000000,d=FR
|
||||
f=401100000,d=CZ
|
||||
f=401400000,d=FR
|
||||
f=401500000,d=AU
|
||||
f=401590000,d=FR
|
||||
f=401600000,d=FR
|
||||
f=402000000,d=BR FR GR IT RS
|
||||
f=402010000,d=TR
|
||||
f=402200000,d=GR
|
||||
f=402500000,d=AU DE
|
||||
f=402740000,d=GR
|
||||
f=402790000,d=RS
|
||||
f=402800000,d=GB IT RS
|
||||
f=402870000,d=BE
|
||||
f=403000000,d=BE BR CZ HU IE IT NL
|
||||
f=403010000,d=DE NL TR
|
||||
f=403150000,d=DE
|
||||
f=403200000,d=HU
|
||||
f=403500000,d=BE HU
|
||||
f=403530000,d=BY
|
||||
f=403600000,d=RO
|
||||
f=403700000,d=BR GB
|
||||
f=403820000,d=RO
|
||||
f=403900000,d=NL
|
||||
f=403920000,d=RO
|
||||
f=403810000,d=DE
|
||||
f=404000000,d=BR CZ ES IT US
|
||||
f=404010000,d=US
|
||||
f=404020000,d=US
|
||||
f=404100000,d=GB
|
||||
f=404300000,d=DE
|
||||
f=404310000,d=DE
|
||||
f=404380000,d=GB
|
||||
f=404400000,d=GB
|
||||
f=404710000,d=DE
|
||||
f=404800000,d=IT
|
||||
f=405000000,d=ES
|
||||
f=405010000,d=FR
|
||||
f=405030000,d=BY
|
||||
f=405100000,d=GB
|
||||
f=405300000,d=BY ES IE SE
|
||||
f=405600000,d=GB
|
||||
f=405680000,d=GB
|
||||
f=405700000,d=DE GB
|
||||
f=405900000,d=DE
|
Loading…
Reference in New Issue
Block a user