diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp index d6d445d3..900a8ed9 100644 --- a/firmware/application/apps/replay_app.cpp +++ b/firmware/application/apps/replay_app.cpp @@ -139,7 +139,12 @@ 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(), sample_rate * 8 , @@ -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, diff --git a/firmware/application/apps/replay_app.hpp b/firmware/application/apps/replay_app.hpp index 9a25ffcf..ac3df3b0 100644 --- a/firmware/application/apps/replay_app.hpp +++ b/firmware/application/apps/replay_app.hpp @@ -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 } diff --git a/firmware/application/apps/ui_about_simple.cpp b/firmware/application/apps/ui_about_simple.cpp index 241bbb4a..6af138ba 100644 --- a/firmware/application/apps/ui_about_simple.cpp +++ b/firmware/application/apps/ui_about_simple.cpp @@ -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; diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index ba080481..25667fe6 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -20,6 +20,8 @@ * Boston, MA 02110-1301, USA. */ +#include + #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,33 +224,49 @@ 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'); - - entry.set_info_string(str_info); - logentry+=str_info+ " "; + " Lat:" + to_string_decimal(entry.pos.latitude, 2) + + " Lon:" + to_string_decimal(entry.pos.longitude, 2); - if (send_updates) + // 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+=log_info + " "; + + // 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(); diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index dd7adb5a..c55ec680 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -36,9 +36,33 @@ using namespace adsb; namespace ui { -#define ADSB_DECAY_A 10 // In seconds -#define ADSB_DECAY_B 30 -#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64 +#define ADSB_DECAY_A 10 // In seconds +#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); } } @@ -137,6 +161,8 @@ public: void update(const AircraftRecentEntry& entry); std::string title() const override { return "Details"; }; + + AircraftRecentEntry get_current_entry() { return entry_copy; } private: AircraftRecentEntry entry_copy { 0 }; diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index db898a69..3c8f2eca 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -48,7 +48,7 @@ void RecentEntriesTable::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); diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index eb728bcf..2fe3fdc2 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -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); diff --git a/firmware/application/apps/ui_freqman.hpp b/firmware/application/apps/ui_freqman.hpp index 4611080b..b65c8433 100644 --- a/firmware/application/apps/ui_freqman.hpp +++ b/firmware/application/apps/ui_freqman.hpp @@ -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 } }; }; diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 7525b8dd..fbda02b7 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -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(); }; diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index c66ccd2b..30acd820 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -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" diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 66e3c576..c8916113 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -22,6 +22,7 @@ #include "ui_sonde.hpp" #include "baseband_api.hpp" +#include "audio.hpp" #include "portapack.hpp" #include @@ -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; }; @@ -107,16 +117,37 @@ SondeView::SondeView(NavigationView& nav) { gps_info.lon, 999); //set a dummy heading out of range to draw a cross...probably not ideal? }; - + logger = std::make_unique(); 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 { diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index 65a397f1..afc2bbec 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -55,7 +55,7 @@ class SondeView : public View { public: static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; - + SondeView(NavigationView& nav); ~SondeView(); @@ -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; }; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index 1e5703e1..59ef942c 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -140,6 +140,9 @@ Continuous (Fox-oring) #include "sd_card.hpp" #include + +#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; @@ -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(); diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 44fc1db7..c4f03855 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -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; diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index c46a8d42..a34d93a6 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -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; diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 60981c70..617f22ac 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -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) { - hackrf::cpld::init_from_eeprom(); - } else { - if( !hackrf::cpld::load_sram() ) { - chSysHalt(); - } - } + + // 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(); } direction = new_direction; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index c3216654..bef08025 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -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(); } diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp index 442034e4..22b02d0b 100644 --- a/firmware/application/string_format.cpp +++ b/firmware/application/string_format.cpp @@ -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) { diff --git a/firmware/application/string_format.hpp b/firmware/application/string_format.hpp index 0555db8e..a588ef95 100644 --- a/firmware/application/string_format.hpp +++ b/firmware/application/string_format.hpp @@ -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); diff --git a/firmware/application/ui/ui_geomap.cpp b/firmware/application/ui/ui_geomap.cpp index 0f4809dc..1d09880d 100644 --- a/firmware/application/ui/ui_geomap.cpp +++ b/firmware/application/ui/ui_geomap.cpp @@ -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); diff --git a/firmware/application/ui/ui_rssi.cpp b/firmware/application/ui/ui_rssi.cpp index 98cfed63..84487b16 100644 --- a/firmware/application/ui/ui_rssi.cpp +++ b/firmware/application/ui/ui_rssi.cpp @@ -75,8 +75,9 @@ 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) { diff --git a/firmware/application/ui/ui_transmitter.cpp b/firmware/application/ui/ui_transmitter.cpp index acc30574..6cfb19bf 100644 --- a/firmware/application/ui/ui_transmitter.cpp +++ b/firmware/application/ui/ui_transmitter.cpp @@ -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, @@ -157,6 +159,10 @@ TransmitterView::TransmitterView( if (on_edit_frequency) 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); diff --git a/firmware/application/ui/ui_transmitter.hpp b/firmware/application/ui/ui_transmitter.hpp index da5ce799..e38aea83 100644 --- a/firmware/application/ui/ui_transmitter.hpp +++ b/firmware/application/ui/ui_transmitter.hpp @@ -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, @@ -152,6 +152,10 @@ private: { 21 * 8, 1 * 8, 9 * 8, 32 }, "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); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index c44e7b6e..e5f7f573 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -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()); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index f7b7f45e..86ea96fb 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -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 { diff --git a/firmware/baseband/dsp_modulate.cpp b/firmware/baseband/dsp_modulate.cpp index d59c7e3e..cc9644bf 100644 --- a/firmware/baseband/dsp_modulate.cpp +++ b/firmware/baseband/dsp_modulate.cpp @@ -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 }; diff --git a/firmware/baseband/proc_aprsrx.cpp b/firmware/baseband/proc_aprsrx.cpp index 56249ce1..6a579ac0 100644 --- a/firmware/baseband/proc_aprsrx.cpp +++ b/firmware/baseband/proc_aprsrx.cpp @@ -141,12 +141,11 @@ 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; - - //if( stream ) { - // const size_t bytes_to_write = sizeof(log) * 1; -// const auto result = stream->write(&log, bytes_to_write); -// } + //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); + //} if(decoded_bit & 0x1){ if(ones_count < 8){ diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index f670dd36..d33b6ea4 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -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(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(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() }; event_dispatcher.run(); + return 0; } diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp index 92e53580..e0c1cb95 100644 --- a/firmware/baseband/proc_sonde.hpp +++ b/firmware/baseband/proc_sonde.hpp @@ -88,19 +88,51 @@ #include "message.hpp" #include "portapack_shared_memory.hpp" +#include "audio_output.hpp" +#include "tone_gen.hpp" + +#include "buffer.hpp" + #include #include #include + +#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 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__*/ diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index bbe5587e..dd74579d 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -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_); } diff --git a/firmware/baseband/tone_gen.hpp b/firmware/baseband/tone_gen.hpp index ef547f26..c1eee222 100644 --- a/firmware/baseband/tone_gen.hpp +++ b/firmware/baseband/tone_gen.hpp @@ -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__ */ diff --git a/firmware/common/adsb.cpp b/firmware/common/adsb.cpp index 862e375d..d1d11707 100644 --- a/firmware/common/adsb.cpp +++ b/firmware/common/adsb.cpp @@ -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 @@ -150,7 +154,19 @@ int cpr_NL(float lat) { return 59 - c; } - return 1; + 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) { @@ -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; diff --git a/firmware/common/adsb.hpp b/firmware/common/adsb.hpp index 82d177e4..7e4d3bce 100644 --- a/firmware/common/adsb.hpp +++ b/firmware/common/adsb.hpp @@ -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); diff --git a/firmware/common/aprs_packet.hpp b/firmware/common/aprs_packet.hpp index e3d76ece..e521a955 100644 --- a/firmware/common/aprs_packet.hpp +++ b/firmware/common/aprs_packet.hpp @@ -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; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 21f40c31..2bee6470 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -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); } diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index df0d7d0d..11643bab 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -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); diff --git a/firmware/common/sine_table_int8.hpp b/firmware/common/sine_table_int8.hpp index 828b6db5..0583fa67 100644 --- a/firmware/common/sine_table_int8.hpp +++ b/firmware/common/sine_table_int8.hpp @@ -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__*/ diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 85ad91f1..79cd7cd4 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -410,23 +410,29 @@ void Labels::paint(Painter& painter) { void LiveDateTime::on_tick_second() { rtcGetTime(&RTCD1, &datetime); text = ""; - - if(date_enabled){ - text = to_string_dec_uint(datetime.month(), 2, '0') + "/" + to_string_dec_uint(datetime.day(), 2, '0') + " "; - } - - text = text + to_string_dec_uint(datetime.hour(), 2, '0') + ":" + to_string_dec_uint(datetime.minute(), 2, '0'); + if(!hide_clock) { + if(date_enabled){ + 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'); - if(seconds_enabled){ - text += ":"; + if(seconds_enabled){ + text += ":"; - if(init_delay==0) - text += to_string_dec_uint(datetime.second(), 2, '0'); - else - { - // Placeholder while the seconds are not updated - text += "XX"; - init_delay--; + if(init_delay==0) + text += to_string_dec_uint(datetime.second(), 2, '0'); + else + { + // Placeholder while the seconds are not updated + text += "XX"; + 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; diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 71cd8f91..18ff7309 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -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; diff --git a/sdcard/FREQMAN/GSM-NL.TXT b/sdcard/FREQMAN/GSM-NL.TXT new file mode 100644 index 00000000..d2fadb1c --- /dev/null +++ b/sdcard/FREQMAN/GSM-NL.TXT @@ -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 \ No newline at end of file diff --git a/sdcard/FREQMAN/ISM.TXT b/sdcard/FREQMAN/ISM.TXT new file mode 100644 index 00000000..41dcad22 --- /dev/null +++ b/sdcard/FREQMAN/ISM.TXT @@ -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 diff --git a/sdcard/FREQMAN/RADIOSONDE.TXT b/sdcard/FREQMAN/RADIOSONDE.TXT new file mode 100644 index 00000000..de308df5 --- /dev/null +++ b/sdcard/FREQMAN/RADIOSONDE.TXT @@ -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 \ No newline at end of file