Compare commits

...

22 Commits

Author SHA1 Message Date
jLynx 3db8a5ac5b Stable v1.8.0 release (#1504)
* Update version.txt

* Update past_version.txt
2023-10-17 15:20:40 +13:00
Mark Thompson 266a626acf POCSAG TX default freq (#1503)
* Changed name for blacklist
* Set default POCSAG TX freq to same as in POCSAG RX
2023-10-16 21:32:07 +02:00
Mark Thompson 411e2fb93a Hide unwanted apps by naming them in SETTINGS/blacklist file (#1502)
* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Changed some app name strings for blacklist
2023-10-15 18:04:26 -05:00
Mark Thompson 6ed83c08e3 Renamed .ini file for Burger Pager app (#1500) 2023-10-14 21:08:39 +02:00
Mark Thompson 9929376acf Added Freq to Radio State, only update specified App Settings, always Load/Save Settings (#1498)
* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload
2023-10-14 11:33:52 -05:00
Mark Thompson 5135b6404d Prevent unnecessary CPLD SRAM load on first RX operation (#1494) 2023-10-14 10:28:44 +02:00
Mark Thompson 790669c242 Added Transmitter settings to 2nd DFU overlay screen (#1497)
* Added Transmitter settings to 2nd DFU overlay
2023-10-14 10:25:40 +02:00
Brumi-2021 4bb8b1882c Error correction. Now comments matching with value (#1496) 2023-10-12 19:56:27 +02:00
Brumi-2021 56702ca7c2 Applying a proper TX_LPF to all remaining TX App (#1495) 2023-10-12 18:02:38 +02:00
Erwin Ried 9be4b9596d Update README.md (#1491)
Changing the introductory video with a newer one with a guy with weird danish accented english
2023-10-12 07:57:34 +02:00
Mark Thompson 37c6b35fb7 Moved external Font Viewer app to DEBUG menu (#1485)
* Updated icon
* Support external apps on DEBUG menu screen
2023-10-11 18:32:01 +02:00
Mark Thompson 5cd7a09797 Disable display scroll before showing fault debug message (#1482) 2023-10-11 07:45:45 +02:00
Mark Thompson a1856b9bb0 Fix some Guru Meditation Faults in ADSB-RX app (#1483)
* Don't use screen_rect in functions called from rtc_timer_tick
* Pause AircraftRecentEntry list changes when AC Details screen is displayed
2023-10-11 07:44:56 +02:00
Mark Thompson 29a36c8658 Revived Fonts Viewer as an External app (in Utilities menu) (#1484)
* Add files via upload
* Moved Font Viewer to external app
2023-10-11 07:43:56 +02:00
gullradriel 264b1b38ba fix complicated timing logic (#1480) 2023-10-09 20:01:40 +02:00
Mark Thompson 65e71508ac Incrementing date workaround for dead RTC battery (#1479)
* Enable f_utime function
* Added file_update_date() function
* Added rtc_battery_workaround() function
* Update ui_navigation.cpp
2023-10-09 12:04:46 +02:00
Mark Thompson e5546159c5 Kludge fix for null parent() (#1477) 2023-10-09 12:03:11 +02:00
gullradriel d7c961ea4f Fixing empty output file/store button/text display (#1475) 2023-10-08 22:21:00 +02:00
Mark Thompson ad987f2b5e Added new icon for IQ Trim, and IQ Trim Button in FileMan (#1476)
* Add files via upload

* Added trim icon

* Added trim icon

* Added Trim button to FileMan

* Added Trim button to FileMan

* Added Trim button to FileMan

* Added Trim button to FileMan
2023-10-08 14:57:59 -05:00
Brumi-2021 defb934c3f Activating TX Low Pass Filter in Second IF IC (#1470)
* Activating TX Low Pass Filter in Second IF IC
* solving PR conversation revisions
* Final TX LPF decision for ADSB_TX
* Small comments correction.
* Added set TX LPF also  in APRS, BurgerPgr,Jammer
2023-10-08 17:50:31 +02:00
Bernd Herzog 5a850984b9 Calculator app (#1474)
* implemented calculator app

* improved output

* refactoring
2023-10-08 16:24:02 +02:00
Bernd Herzog 1185b67b28 changed alignment for text sections (#1473) 2023-10-07 15:30:43 +02:00
109 changed files with 3196 additions and 341 deletions
+1 -1
View File
@@ -1 +1 @@
v1.7.3
v1.7.4
+1 -1
View File
@@ -1 +1 @@
v1.7.4
v1.8.0
+3 -3
View File
@@ -8,11 +8,11 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw
*[PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_DmU7GQX) (clone) with a custom [3d printed case](https://github.com/eried/portapack-mayhem/wiki/H2-Enclosure)*
# Quick overview
# What is this?
If you are new to *HackRF+PortaPack+Mayhem*, there is an awesome introductory video by [Tech Minds](https://www.youtube.com/channel/UC9a8Z6Sp6eb2s3O79pX5Zvg) available:
If you are new to *HackRF+PortaPack+Mayhem*, check this video:
[![Setup and overview](https://img.youtube.com/vi/kjFB58Y1TAo/0.jpg)](https://www.youtube.com/watch?v=kjFB58Y1TAo)
[![What is?](https://img.youtube.com/vi/alrFbY5vxt4/0.jpg)](https://www.youtube.com/watch?v=alrFbY5vxt4)
# Frequently Asked Questions
+35 -39
View File
@@ -244,8 +244,7 @@ SettingsManager::SettingsManager(
: app_name_{app_name},
settings_{},
bindings_{},
loaded_{false},
radio_loaded_{false} {
loaded_{false} {
settings_.mode = mode;
settings_.options = options;
@@ -253,53 +252,50 @@ SettingsManager::SettingsManager(
additional_settings.reserve(17 + additional_settings.size());
bindings_ = std::move(additional_settings);
// Additional settings should always be loaded because apps now rely
// on being able to store UI settings, config, etc. The radio settings
// are only loaded if the global option has been enabled.
// Add the radio setting bindings if either load or save are enabled.
if (portapack::persistent_memory::load_app_settings() ||
portapack::persistent_memory::save_app_settings()) {
// Transmitter model settings.
if (flags_enabled(mode, Mode::TX)) {
bindings_.emplace_back("tx_frequency"sv, &settings_.tx_frequency);
bindings_.emplace_back("tx_amp"sv, &settings_.tx_amp);
bindings_.emplace_back("tx_gain"sv, &settings_.tx_gain);
bindings_.emplace_back("channel_bandwidth"sv, &settings_.channel_bandwidth);
}
// Settings should always be loaded because apps now rely
// on being able to store UI settings, config, etc.
// Receiver model settings.
if (flags_enabled(mode, Mode::RX)) {
bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency);
bindings_.emplace_back("lna"sv, &settings_.lna);
bindings_.emplace_back("vga"sv, &settings_.vga);
bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp);
bindings_.emplace_back("modulation"sv, &settings_.modulation);
bindings_.emplace_back("am_config_index"sv, &settings_.am_config_index);
bindings_.emplace_back("nbfm_config_index"sv, &settings_.nbfm_config_index);
bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index);
bindings_.emplace_back("squelch"sv, &settings_.squelch);
}
// Common model settings.
bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth);
bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate);
bindings_.emplace_back("step"sv, &settings_.step);
bindings_.emplace_back("volume"sv, &settings_.volume);
// Transmitter model settings.
if (flags_enabled(mode, Mode::TX)) {
bindings_.emplace_back("tx_frequency"sv, &settings_.tx_frequency);
bindings_.emplace_back("tx_amp"sv, &settings_.tx_amp);
bindings_.emplace_back("tx_gain"sv, &settings_.tx_gain);
bindings_.emplace_back("channel_bandwidth"sv, &settings_.channel_bandwidth);
}
// Receiver model settings.
if (flags_enabled(mode, Mode::RX)) {
bindings_.emplace_back("rx_frequency"sv, &settings_.rx_frequency);
bindings_.emplace_back("lna"sv, &settings_.lna);
bindings_.emplace_back("vga"sv, &settings_.vga);
bindings_.emplace_back("rx_amp"sv, &settings_.rx_amp);
bindings_.emplace_back("modulation"sv, &settings_.modulation);
bindings_.emplace_back("am_config_index"sv, &settings_.am_config_index);
bindings_.emplace_back("nbfm_config_index"sv, &settings_.nbfm_config_index);
bindings_.emplace_back("wfm_config_index"sv, &settings_.wfm_config_index);
bindings_.emplace_back("squelch"sv, &settings_.squelch);
}
// Common model settings.
bindings_.emplace_back("baseband_bandwidth"sv, &settings_.baseband_bandwidth);
bindings_.emplace_back("sampling_rate"sv, &settings_.sampling_rate);
bindings_.emplace_back("step"sv, &settings_.step);
bindings_.emplace_back("volume"sv, &settings_.volume);
// RadioState should have initialized default radio parameters before this function;
// copy them to settings_ before checking settings .ini file (in case the file doesn't exist
// or doesn't include all parameters). Settings in the file can overwrite all, or a subset of parameters.
copy_from_radio_model(settings_);
loaded_ = load_settings(app_name_, bindings_);
// Only copy to the radio if load was successful.
if (loaded_ && portapack::persistent_memory::load_app_settings()) {
radio_loaded_ = true;
if (loaded_)
copy_to_radio_model(settings_);
}
}
SettingsManager::~SettingsManager() {
// Only save radio settings when the option is enabled.
if (portapack::persistent_memory::save_app_settings())
copy_from_radio_model(settings_);
copy_from_radio_model(settings_);
save_settings(app_name_, bindings_);
}
-3
View File
@@ -170,8 +170,6 @@ class SettingsManager {
/* True if settings were successfully loaded from file. */
bool loaded() const { return loaded_; }
/* True if radio settings were successfully loaded from file. */
bool radio_loaded() const { return radio_loaded_; }
Mode mode() const { return settings_.mode; }
AppSettings& raw() { return settings_; }
@@ -181,7 +179,6 @@ class SettingsManager {
AppSettings settings_;
SettingBindings bindings_;
bool loaded_;
bool radio_loaded_;
};
} // namespace app_settings
+2 -1
View File
@@ -60,11 +60,12 @@ class ACARSAppView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
131550000 /* frequency */,
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_acars.hpp", app_settings::Mode::RX};
"rx_acars", app_settings::Mode::RX};
bool logging{false};
uint32_t packet_counter{0};
-3
View File
@@ -382,9 +382,6 @@ AISAppView::AISAppView(NavigationView& nav)
recent_entry_detail_view.hidden(true);
if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable();
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
+1 -2
View File
@@ -162,9 +162,8 @@ class AISAppView : public View {
std::string title() const override { return "AIS RX"; };
private:
static constexpr uint32_t initial_target_frequency = 162025000;
RxRadioState radio_state_{
162025000 /* frequency*/,
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
-3
View File
@@ -110,9 +110,6 @@ ERTAppView::ERTAppView(NavigationView&) {
&recent_entries_view,
});
if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable();
logger = std::make_unique<ERTLogger>();
+1 -2
View File
@@ -123,12 +123,11 @@ class ERTAppView : public View {
std::string title() const override { return "ERT RX"; };
private:
static constexpr uint32_t initial_target_frequency = 911600000;
ERTRecentEntries recent{};
std::unique_ptr<ERTLogger> logger{};
RxRadioState radio_state_{
911600000 /* frequency */,
2500000 /* bandwidth */,
4194304 /* sampling rate */};
app_settings::SettingsManager settings_{
+4 -6
View File
@@ -74,7 +74,10 @@ void GpsSimAppView::on_file_changed(const fs::path& new_file_path) {
auto duration = ms_duration(file_size, transmitter_model.sampling_rate(), 2);
text_duration.set(to_string_time_ms(duration));
button_play.focus();
// TODO: fix in UI framework with 'try_focus()'?
// Hack around focus getting called by ctor before parent is set.
if (parent())
button_play.focus();
}
void GpsSimAppView::on_tx_progress(const uint32_t progress) {
@@ -173,11 +176,6 @@ GpsSimAppView::GpsSimAppView(
&waterfall,
});
if (!settings_.radio_loaded()) {
field_frequency.set_value(initial_target_frequency);
transmitter_model.set_sampling_rate(2600000);
}
field_frequency.set_step(5000);
button_play.on_select = [this](ImageButton&) {
+4 -8
View File
@@ -51,21 +51,17 @@ class GpsSimAppView : public View {
std::string title() const override { return "GPS Sim TX"; };
private:
static constexpr uint32_t initial_target_frequency = 1575420000;
NavigationView& nav_;
RxRadioState radio_state_{
3000000 /* bandwidth */,
500000 /* sampling rate */
TxRadioState radio_state_{
1575420000 /* frequency */,
15000000 /* bandwidth */,
2600000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_gps", app_settings::Mode::TX};
static constexpr ui::Dim header_height = 3 * 16;
int32_t tx_gain{47};
bool rf_amp{true}; // aux private var to store temporal, same as Replay App rf_amp user selection.
static constexpr uint32_t baseband_bandwidth = 3000000; // filter bandwidth
const size_t read_size{16384};
const size_t buffer_count{3};
+4
View File
@@ -238,6 +238,10 @@ void LGEView::start_tx() {
tx_view.set_dirty();
}
/* By experimental test, previous fw 1.7.4 seems to have setting , tx LPF = 5Mhz
This LGE - seems to be for controlling a "laser tag equipment" (Havoc app) , modulated FSK , low bauds,
and using max GUI fm dev 150k , we are still in NBFM, let's reduce slightly original TX LPF 5M ->2M5*/
transmitter_model.set_baseband_bandwidth(2'500'000);
transmitter_model.enable();
chThdSleep(100);
+1
View File
@@ -51,6 +51,7 @@ class LGEView : public View {
};
TxRadioState radio_state_{
868067000 /* frequency */,
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
-3
View File
@@ -114,9 +114,6 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav)
? FILTER_NONE
: FILTER_DROP;
}
if (!app_settings_.radio_loaded()) {
field_frequency.set_value(initial_target_frequency);
}
logger.append(LOG_ROOT_DIR "/POCSAG.TXT");
+5 -2
View File
@@ -197,14 +197,17 @@ class POCSAGAppView : public View {
void focus() override;
private:
static constexpr uint32_t initial_target_frequency = 466'175'000;
bool logging() const { return settings_.enable_logging; };
bool logging_raw() const { return settings_.enable_raw_log; };
bool hide_bad_data() const { return settings_.hide_bad_data; };
bool hide_addr_only() const { return settings_.hide_addr_only; };
NavigationView& nav_;
RxRadioState radio_state_{};
RxRadioState radio_state_{
466175000 /* frequency*/,
max283x::filter::bandwidth_minimum /* bandwidth */,
3072000 /* sampling rate */
};
// Settings
POCSAGSettings settings_{};
@@ -50,6 +50,7 @@ class SoundBoardView : public View {
private:
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
-3
View File
@@ -157,9 +157,6 @@ TPMSAppView::TPMSAppView(NavigationView&) {
&field_vga,
&recent_entries_view});
if (!settings_.radio_loaded())
receiver_model.set_target_frequency(initial_target_frequency);
receiver_model.enable();
options_band.on_change = [this](size_t, OptionsField::value_t v) {
+2 -3
View File
@@ -102,9 +102,8 @@ class TPMSAppView : public View {
std::string title() const override { return "TPMS RX"; };
private:
static constexpr uint32_t initial_target_frequency = 315000000;
RxRadioState radio_state_{
315000000 /* frequency*/,
1750000 /* bandwidth */,
2457600 /* sampling rate */};
app_settings::SettingsManager settings_{
@@ -135,7 +134,7 @@ class TPMSAppView : public View {
3,
{
{"315", 315000000},
{"433", 433920000},
{"434", 433920000},
}};
OptionsField options_pressure{
+10 -1
View File
@@ -34,6 +34,8 @@ using namespace portapack;
namespace ui {
bool ac_details_view_active{false};
template <>
void RecentEntriesTable<AircraftRecentEntries>::draw(
const Entry& entry,
@@ -182,6 +184,7 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
break;
}
button_close.on_select = [&nav](Button&) {
ac_details_view_active = false;
nav.pop();
};
};
@@ -217,6 +220,7 @@ void ADSBRxDetailsView::update(const AircraftRecentEntry& entry) {
}
ADSBRxDetailsView::~ADSBRxDetailsView() {
ac_details_view_active = false;
on_close_();
}
@@ -260,6 +264,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));
button_aircraft_details.on_select = [this, &nav](Button&) {
ac_details_view_active = true;
aircraft_details_view = nav.push<ADSBRxAircraftDetailsView>(entry_copy, [this]() { send_updates = false; });
send_updates = false;
};
@@ -433,6 +438,11 @@ void ADSBRxView::updateDetailsAndMap(int ageStep) {
ui::GeoMarker marker;
bool storeNewMarkers = false;
// NB: Temporarily pausing updates in rtc_timer_tick context when viewing AC Details screen (kludge for some Guru faults)
// TODO: More targeted blocking of updates in rtc_timer_tick when ADSB processes are running
if (ac_details_view_active)
return;
// Sort and truncate the entries, grouped, newest group first
sort_entries_by_state();
truncate_entries(recent);
@@ -511,7 +521,6 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
baseband::set_adsb();
receiver_model.set_target_frequency(1'090'000'000);
receiver_model.enable();
}
+1
View File
@@ -342,6 +342,7 @@ class ADSBRxView : public View {
private:
RxRadioState radio_state_{
1090000000 /* frequency */,
2500000 /* bandwidth */,
2000000 /* sampling rate */,
ReceiverModel::Mode::SpectrumAnalysis};
+3
View File
@@ -296,6 +296,9 @@ void ADSBTxView::generate_frames() {
void ADSBTxView::start_tx() {
generate_frames();
/* Already tested , with SDR Angel + another Hackrf RX and dump1090 + SDR RLT. Final conclusion is TX LPF 6 Mhz is
* the best settings to fulfill ADSB transponder spectrum mask requirements (<=-20 dB's at +-7Mhz , <=-40 dB's at +-23Mhz )
* and not showing any ADSB data decoding degradation.*/
transmitter_model.enable();
baseband::set_adsb();
+2 -1
View File
@@ -203,7 +203,8 @@ class ADSBTxView : public View {
};*/
TxRadioState radio_state_{
10000000 /* bandwidth */,
1090000000 /* frequency */,
6000000 /* bandwidth */,
4000000 /* sampling rate */
};
app_settings::SettingsManager settings_{
+5 -1
View File
@@ -190,7 +190,11 @@ class APRSRxView : public View {
bool reset_console = false;
NavigationView& nav_;
RxRadioState radio_state_{};
RxRadioState radio_state_{
144390000 /* frequency */,
1750000 /* bandwidth */,
3072000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"rx_aprs", app_settings::Mode::RX};
+1
View File
@@ -46,6 +46,7 @@ class APRSTXView : public View {
private:
TxRadioState radio_state_{
144390000 /* frequency */,
1750000 /* bandwidth */,
AFSK_TX_SAMPLERATE /* sampling rate */
};
-1
View File
@@ -54,7 +54,6 @@ BTLERxView::BTLERxView(NavigationView& nav)
&console});
// Auto-configure modem for LCR RX (TODO: remove later)
field_frequency.set_value(2426000000);
auto def_bell202 = &modem_defs[0];
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
serial_format_t serial_format;
+1
View File
@@ -50,6 +50,7 @@ class BTLERxView : public View {
NavigationView& nav_;
RxRadioState radio_state_{
2426000000 /* frequency */,
4000000 /* bandwidth */,
4000000 /* sampling rate */,
ReceiverModel::Mode::WidebandFMAudio};
+2 -1
View File
@@ -52,11 +52,12 @@ class CoasterPagerView : public View {
tx_modes tx_mode = IDLE;
TxRadioState radio_state_{
433920000, /* frequency */
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
app_settings::SettingsManager settings_{
"tx_coaster", app_settings::Mode::TX};
"tx_burger", app_settings::Mode::TX};
void start_tx();
void generate_frame();
+6 -36
View File
@@ -34,6 +34,7 @@
#include "ui_font_fixed_8x16.hpp"
#include "ui_styles.hpp"
#include "ui_painter.hpp"
#include "ui_external_items_menu_loader.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
@@ -400,7 +401,6 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
add_items({
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav]() { nav.push<DebugControlsView>(); }},
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { portapack::persistent_memory::debug_dump(); }},
//{"Fonts Viewer", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<DebugFontsView>(); }}, // temporarily disabled to conserve ROM space
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { stack_dump(); }},
{"Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
{"P.Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
@@ -410,6 +410,11 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
{"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<DebugScreenTest>(); }},
});
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav)) {
add_item(gridItem);
};
set_max_rows(2); // allow wider buttons
}
@@ -469,41 +474,6 @@ uint32_t DebugPmemView::registers_widget_feed(const size_t register_number) {
return data.regfile[(page_size * page + register_number) / 4] >> (register_number % 4 * 8);
}
/* DebugFontsView *******************************************************/
uint16_t DebugFontsView::display_font(Painter& painter, uint16_t y_offset, const Style* font_style, std::string_view font_name) {
auto char_width{font_style->font.char_width()};
auto char_height{font_style->font.line_height()};
auto cpl{((screen_width / char_width) - 6) & 0xF8}; // Display a multiple of 8 characters per line
uint16_t line_pos{y_offset};
painter.draw_string({0, y_offset}, *font_style, font_name);
// Displaying ASCII+extended characters from 0x20 to 0xFF
for (uint8_t c = 0; c <= 0xDF; c++) {
line_pos = y_offset + ((c / cpl) + 2) * char_height;
if ((c % cpl) == 0)
painter.draw_string({0, line_pos}, *font_style, "Ox" + to_string_hex(c + 0x20, 2));
painter.draw_char({((c % cpl) + 5) * char_width, line_pos}, *font_style, (char)(c + 0x20));
}
return line_pos + char_height;
}
void DebugFontsView::paint(Painter& painter) {
int16_t line_pos;
line_pos = display_font(painter, 32, &Styles::white, "Fixed 8x16");
display_font(painter, line_pos + 16, &Styles::white_small, "Fixed 5x8");
}
DebugFontsView::DebugFontsView(NavigationView& nav)
: nav_{nav} {
set_focusable(true);
}
/* DebugScreenTest ****************************************************/
DebugScreenTest::DebugScreenTest(NavigationView& nav)
-11
View File
@@ -310,17 +310,6 @@ class DebugPmemView : public View {
uint32_t registers_widget_feed(const size_t register_number);
};
class DebugFontsView : public View {
public:
DebugFontsView(NavigationView& nav);
void paint(Painter& painter) override;
std::string title() const override { return "Fonts"; };
private:
uint16_t display_font(Painter& painter, uint16_t y_offset, const Style* font_style, std::string_view font_name);
NavigationView& nav_;
};
class DebugScreenTest : public View {
public:
DebugScreenTest(NavigationView& nav);
+7 -3
View File
@@ -92,7 +92,9 @@ DfuMenu2::DfuMenu2(NavigationView& nav)
&text_info_line_5,
&text_info_line_6,
&text_info_line_7,
&text_info_line_8});
&text_info_line_8,
&text_info_line_9,
&text_info_line_10});
}
void DfuMenu2::paint(Painter& painter) {
@@ -103,10 +105,12 @@ void DfuMenu2::paint(Painter& painter) {
text_info_line_5.set(to_string_dec_uint(portapack::receiver_model.am_configuration(), 10));
text_info_line_6.set(to_string_dec_uint(portapack::receiver_model.nbfm_configuration(), 10));
text_info_line_7.set(to_string_dec_uint(portapack::receiver_model.wfm_configuration(), 10));
text_info_line_8.set("");
text_info_line_8.set(to_string_dec_uint(portapack::transmitter_model.target_frequency(), 10));
text_info_line_9.set(to_string_dec_uint(portapack::transmitter_model.baseband_bandwidth(), 10));
text_info_line_10.set(to_string_dec_uint(portapack::transmitter_model.sampling_rate(), 10));
constexpr auto margin = 5;
constexpr auto lines = 8 + 2;
constexpr auto lines = 10 + 2;
painter.fill_rectangle(
{{5 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},
+9 -5
View File
@@ -77,17 +77,19 @@ class DfuMenu2 : public View {
private:
NavigationView& nav_;
Text text_head{{6 * CHARACTER_WIDTH, 3 * LINE_HEIGHT, 8 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, "Receiver"};
Text text_head{{6 * CHARACTER_WIDTH, 3 * LINE_HEIGHT, 14 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, "Radio Settings"};
Labels labels{
{{5 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "Tgt freq:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "Bandwidt:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "Sampl Rt:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "RX Freq:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "RX BW:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "RX SampR:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 8 * LINE_HEIGHT}, "Modulatn:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 9 * LINE_HEIGHT}, "AM cfg:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 10 * LINE_HEIGHT}, "NBFM cfg:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "WFM cfg:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "", Color::dark_cyan()}};
{{5 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "TX Freq:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "TX BW:", Color::dark_cyan()},
{{5 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "TX SampR:", Color::dark_cyan()}};
Text text_info_line_1{{14 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_2{{14 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
@@ -97,6 +99,8 @@ class DfuMenu2 : public View {
Text text_info_line_6{{14 * CHARACTER_WIDTH, 10 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_7{{14 * CHARACTER_WIDTH, 11 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_8{{14 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_9{{14 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_10{{14 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 10 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
};
} /* namespace ui */
@@ -269,6 +269,9 @@ void EncodersView::start_tx(const bool scan) {
repeat_index = 1;
update_progress();
/* Setting TX LPF 1M75 in this TX OOK App , We got same results as fw 1.7.4
* Looking max BW of this app, we tested , Selecting OOK type 145026 with CLK 455K and max DEV. 150k,
* and we got BW +-2Mhz , with that TX LPF 1M75, it is fine.*/
transmitter_model.enable();
baseband::set_ook_data(
@@ -185,6 +185,7 @@ class EncodersView : public View {
};
TxRadioState radio_state_{
433920000 /* frequency */,
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
+10
View File
@@ -30,6 +30,7 @@
#include "ui_remote.hpp"
#include "ui_ss_viewer.hpp"
#include "ui_text_editor.hpp"
#include "ui_iq_trim.hpp"
#include "string_format.hpp"
#include "portapack.hpp"
#include "event_m0.hpp"
@@ -566,6 +567,7 @@ FileManagerView::FileManagerView(
&button_new_file,
&button_open_notepad,
&button_rename_timestamp,
&button_open_iq_trim,
});
menu_view.on_highlight = [this]() {
@@ -648,6 +650,14 @@ FileManagerView::FileManagerView(
} else
nav_.display_modal("Timestamp Rename", "Can't rename that.");
};
button_open_iq_trim.on_select = [this]() {
auto path = get_selected_full_path();
if (selected_is_valid() && !get_selected_entry().is_directory && is_cxx_capture_file(path)) {
nav_.push<IQTrimView>(path);
} else
nav_.display_modal("IQ Trim", "Not a capture file.");
};
}
} // namespace ui
+6
View File
@@ -272,6 +272,12 @@ class FileManagerView : public FileManBaseView {
&bitmap_icon_options_datetime,
Color::orange(),
/*vcenter*/ true};
NewButton button_open_iq_trim{
{9 * 8, 34 * 8, 4 * 8, 32},
{},
&bitmap_icon_trim,
Color::orange()};
};
} /* namespace ui */
+13 -4
View File
@@ -47,10 +47,7 @@ IQTrimView::IQTrimView(NavigationView& nav)
auto open_view = nav_.push<FileLoadView>(".C*");
open_view->push_dir(u"CAPTURES");
open_view->on_changed = [this](fs::path path) {
path_ = std::move(path);
profile_capture();
compute_range();
refresh_ui();
open_file(path);
};
};
@@ -84,6 +81,18 @@ IQTrimView::IQTrimView(NavigationView& nav)
};
}
IQTrimView::IQTrimView(NavigationView& nav, const fs::path& path)
: IQTrimView(nav) {
open_file(path);
}
void IQTrimView::open_file(const std::filesystem::path& path) {
path_ = std::move(path);
profile_capture();
compute_range();
refresh_ui();
}
void IQTrimView::paint(Painter& painter) {
if (info_) {
uint32_t power_cutoff = field_cutoff.value() * static_cast<uint64_t>(info_->max_power) / 100;
+3
View File
@@ -68,12 +68,15 @@ class TrimProgressUI {
class IQTrimView : public View {
public:
IQTrimView(NavigationView& nav);
IQTrimView(NavigationView& nav, const std::filesystem::path& path);
std::string title() const override { return "IQ Trim"; }
void paint(Painter& painter) override;
void focus() override;
private:
void open_file(const std::filesystem::path& path);
/* Update controls with latest values. */
void refresh_ui();
+3 -1
View File
@@ -261,6 +261,7 @@ void JammerView::start_tx() {
transmitter_model.set_rf_amp(field_amp.value());
transmitter_model.set_tx_gain(field_gain.value());
transmitter_model.set_baseband_bandwidth(28'000'000); // Although tx is narrowband , let's use Max TX LPF .
transmitter_model.enable();
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
@@ -288,7 +289,8 @@ void JammerView::on_timer() {
mscounter = 0;
if (jamming) {
if (cooling) {
if (++seconds >= field_timepause.value()) { // Re-start TX
if (++seconds >= field_timepause.value()) { // Re-start TX
transmitter_model.set_baseband_bandwidth(28'000'000); // Although tx is narrowband , let's use Max TX LPF .
transmitter_model.enable();
button_transmit.set_text("STOP");
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
+1
View File
@@ -101,6 +101,7 @@ class JammerView : public View {
private:
NavigationView& nav_;
TxRadioState radio_state_{
0 /* frequency */,
3500000 /* bandwidth */,
3072000 /* sampling rate */
};
-2
View File
@@ -222,8 +222,6 @@ KeyfobView::KeyfobView(
options_make.set_selected_index(0);
transmitter_model.set_target_frequency(433920000); // Fixed 433.92MHz
tx_view.on_edit_frequency = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(transmitter_model.target_frequency());
new_view->on_changed = [this](rf::Frequency f) {
+1
View File
@@ -44,6 +44,7 @@ class KeyfobView : public View {
NavigationView& nav_;
TxRadioState radio_state_{
433920000 /* frequency */,
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
+2
View File
@@ -127,6 +127,8 @@ void LCRView::start_tx(const bool scan) {
modems::generate_data(lcr::generate_message(rgsb, litterals_list, options_ec.selected_index()), lcr_message_data);
/* It is AFSK modulation , measuring original fw 1.7.4 spectrum BW is just around 30khz , NBFM */
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF 1M75, same spectrum as previous fw 1.7.4
transmitter_model.enable();
memcpy(shared_memory.bb_data.data, lcr_message_data, sizeof(lcr_message_data));
+1
View File
@@ -82,6 +82,7 @@ class LCRView : public View {
};
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
AFSK_TX_SAMPLERATE /* sampling rate */
};
+4
View File
@@ -87,6 +87,10 @@ void MicTXView::set_tx(bool enable) {
transmitting = true;
configure_baseband();
transmitter_model.set_target_frequency(tx_frequency); // Now, no need: transmitter_model.set_tx_gain(tx_gain), nor (rf_amp);
/* The max. Power Spectrum Densitiy in WFM with High tone mod level (80%) and high 32kHZ subtone as fmod. with max fdeviation 150k ,
BW aprox = 2 *(150K + 32K) = 364khz, then we just select the minimum TX LPF 1M75. */
transmitter_model.set_baseband_bandwidth(1'750'000);
transmitter_model.enable();
portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming
} else {
+1
View File
@@ -82,6 +82,7 @@ class MicTXView : public View {
RxRadioState rx_radio_state_{};
TxRadioState tx_radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
sampling_rate /* sampling rate */
};
+2
View File
@@ -117,6 +117,8 @@ bool MorseView::start_tx() {
}
progressbar.set_max(symbol_count);
// By experimental spectrum measurment, we left exactly same TX LPF settings as previous fw 1.7.4, TX LPF= 1M75 (min).
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF .already tested in FM morse max tone 9,999k , max dev 150khz
transmitter_model.enable();
if (modulation == CW) {
+1
View File
@@ -70,6 +70,7 @@ class MorseView : public View {
uint32_t time_units{0};
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
-1
View File
@@ -54,7 +54,6 @@ NRFRxView::NRFRxView(NavigationView& nav)
&console});
// Auto-configure modem for LCR RX (will be removed later)
field_frequency.set_value(2480000000);
auto def_bell202 = &modem_defs[0];
persistent_memory::set_modem_baudrate(def_bell202->baudrate);
serial_format_t serial_format;
+1
View File
@@ -50,6 +50,7 @@ class NRFRxView : public View {
NavigationView& nav_;
RxRadioState radio_state_{
2480000000 /* frequency */,
4000000 /* bandwidth */,
4000000 /* sampling rate */,
ReceiverModel::Mode::WidebandFMAudio};
+1
View File
@@ -56,6 +56,7 @@ class NumbersStationView : public View {
NavigationView& nav_;
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
+1
View File
@@ -56,6 +56,7 @@ class NuoptixView : public View {
};
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
+1 -1
View File
@@ -273,7 +273,7 @@ void PlaylistView::send_current_track() {
// ReplayThread starts immediately on construction; must be set before creating.
transmitter_model.set_target_frequency(current()->metadata.center_frequency);
transmitter_model.set_sampling_rate(get_actual_sample_rate(current()->metadata.sample_rate));
transmitter_model.set_baseband_bandwidth(baseband_bandwidth);
transmitter_model.set_baseband_bandwidth(current()->metadata.sample_rate <= 500'000 ? 1'750'000 : 2'500'000); // TX LPF min 1M75 for SR <=500K, and 2M5 (by experimental test) for SR >500K
transmitter_model.enable();
// Reset the transmit progress bar.
@@ -60,7 +60,6 @@ class PlaylistView : public View {
// More header == less spectrum view.
static constexpr ui::Dim header_height = 6 * 16;
static constexpr uint32_t baseband_bandwidth = 2'500'000;
struct playlist_entry {
std::filesystem::path path{};
@@ -81,6 +81,8 @@ bool POCSAGTXView::start_tx() {
transmitter_model.set_rf_amp(true);
transmitter_model.set_tx_gain(40);
// We left exactly same TX LPF settings as previous fw 1.7.4, TX LPF= 1M75 (min). It is fine even in max FM dev. 150khz and 2400 bauds.
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF . Pocsag is NBFM , using BW channel 25khz or 12khz
transmitter_model.enable();
uint8_t* data_ptr = shared_memory.bb_data.data;
@@ -60,6 +60,7 @@ class POCSAGTXView : public View {
NavigationView& nav_;
TxRadioState radio_state_{
466175000 /* frequency */,
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
+1
View File
@@ -142,6 +142,7 @@ class RDSView : public View {
RDS_flags rds_flags{};
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
2280000 /* sampling rate */
};
+31 -43
View File
@@ -103,7 +103,6 @@ void ReconView::reset_indexes() {
void ReconView::update_description() {
if (frequency_list.empty() || current_entry().description.empty()) {
description = "...no description...";
return;
} else {
switch (current_entry().type) {
case freqman_type::Range:
@@ -117,7 +116,6 @@ void ReconView::update_description() {
}
description += current_entry().description;
}
desc_cycle.set(description);
}
@@ -496,6 +494,7 @@ ReconView::ReconView(NavigationView& nav)
button_manual_recon.on_select = [this](Button&) {
button_remove.set_text("DELETE");
button_add.hidden(false);
scanner_mode = false;
manual_mode = true;
recon_pause();
@@ -539,7 +538,7 @@ ReconView::ReconView(NavigationView& nav)
button_scanner_mode.set_style(&Styles::white);
button_scanner_mode.set_text("MANUAL");
file_name.set_style(&Styles::white);
file_name.set("MANUAL RANGE RECON");
file_name.set("MANUAL => " + output_file);
desc_cycle.set_style(&Styles::white);
last_entry.modulation = freqman_invalid_index;
@@ -608,12 +607,12 @@ ReconView::ReconView(NavigationView& nav)
scanner_mode = false;
button_scanner_mode.set_style(&Styles::blue);
button_scanner_mode.set_text("RECON");
button_remove.set_text("DELETE");
button_remove.set_text("REMOVE");
} else {
scanner_mode = true;
button_scanner_mode.set_style(&Styles::red);
button_scanner_mode.set_text("SCAN");
button_scanner_mode.set_text("REMOVE");
button_remove.set_text("DELETE");
}
frequency_file_load(true);
if (autostart) {
@@ -621,12 +620,17 @@ ReconView::ReconView(NavigationView& nav)
} else {
recon_pause();
}
button_add.hidden(scanner_mode);
if (scanner_mode) // only needed when hiding, UI mayhem
set_dirty();
};
button_config.on_select = [this, &nav](Button&) {
if (is_recording) // disabling config while recording
return;
clear_freqlist_for_ui_action();
freq_lock = 0;
timer = 0;
auto open_view = nav.push<ReconSetupView>(input_file, output_file);
@@ -733,30 +737,22 @@ void ReconView::frequency_file_load(bool) {
button_scanner_mode.set_text("RECON");
}
file_name.set(file_input + "=>" + output_file);
freqman_load_options options{
.load_freqs = load_freqs,
.load_ranges = load_ranges,
.load_hamradios = load_hamradios};
if (!load_freqman_file(file_input, frequency_list, options)) {
if (!load_freqman_file(file_input, frequency_list, options) || frequency_list.empty()) {
file_name.set_style(&Styles::red);
desc_cycle.set(" NO " + file_input + ".TXT FILE ...");
file_name.set("=> NO DATA");
} else {
file_name.set(file_input + "=>" + output_file);
if (frequency_list.size() == 0) {
file_name.set_style(&Styles::red);
desc_cycle.set("/0 no entries in list");
file_name.set("BadOrEmpty " + file_input);
} else {
if (frequency_list.size() > FREQMAN_MAX_PER_FILE) {
file_name.set_style(&Styles::yellow);
}
}
desc_cycle.set("...empty file...");
frequency_list.clear();
text_cycle.set_text(" ");
return;
}
if (frequency_list.empty()) {
text_cycle.set_text(" ");
return; // Can't really do much.
if (frequency_list.size() > FREQMAN_MAX_PER_FILE) {
file_name.set_style(&Styles::yellow);
}
reset_indexes();
@@ -781,19 +777,8 @@ void ReconView::frequency_file_load(bool) {
}
void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
systime_t time_interval = 100;
uint32_t local_recon_lock_duration = recon_lock_duration;
chrono_end = chTimeNow();
if (field_mode.selected_index_value() == SPEC_MODULATION) {
time_interval = chrono_end - chrono_start;
if (field_lock_wait.value() == 0) {
if (time_interval <= 1) // capping here to avoid freeze because too quick
local_recon_lock_duration = 2; // minimum working tested value
else
local_recon_lock_duration = time_interval;
}
}
systime_t time_interval = chrono_end - chrono_start;
chrono_start = chrono_end;
// hack to reload the list if it was cleared by going into CONFIG
@@ -813,7 +798,7 @@ void ReconView::on_statistics_update(const ChannelStatistics& statistics) {
if (!timer) {
status = 0;
freq_lock = 0;
timer = local_recon_lock_duration;
timer = recon_lock_duration;
}
if (freq_lock < recon_lock_nb_match) // LOCKING
{
@@ -1214,14 +1199,6 @@ void ReconView::handle_remove_current_item() {
if (current_is_valid()) {
frequency_list.erase(frequency_list.begin() + current_index);
}
if (frequency_list.size() > 0) {
current_index = clip<int32_t>(current_index, 0u, frequency_list.size() - 1);
text_cycle.set_text(to_string_dec_uint(current_index + 1, 3));
update_description();
} else {
current_index = 0;
}
}
// In Scanner or Manual mode, remove the entry from the output file.
@@ -1232,6 +1209,17 @@ void ReconView::handle_remove_current_item() {
freq_db.delete_entry(entry);
}
// Clip
if (frequency_list.size() > 0) {
current_index = clip<int32_t>(current_index, 0u, frequency_list.size() - 1);
text_cycle.set_text(to_string_dec_uint(current_index + 1, 3));
} else {
current_index = 0;
text_cycle.set_text(" ");
}
update_description();
}
} /* namespace ui */
+1 -1
View File
@@ -303,7 +303,7 @@ class ReconView : public View {
NumberField field_lock_wait{
{25 * 8, 24 * 8 + 4},
4,
{0, RECON_MAX_LOCK_DURATION},
{STATS_UPDATE_INTERVAL, RECON_MAX_LOCK_DURATION},
STATS_UPDATE_INTERVAL,
' ',
};
+1
View File
@@ -90,6 +90,7 @@ class SearchView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
100'000'000 /* frequency */,
2500000 /* bandwidth */,
SEARCH_SLICE_WIDTH /* sampling rate */,
ReceiverModel::Mode::SpectrumAnalysis};
-29
View File
@@ -343,34 +343,6 @@ void SetUIView::focus() {
button_save.focus();
}
/* SetAppSettingsView ************************************/
SetAppSettingsView::SetAppSettingsView(NavigationView& nav) {
add_children({
&labels,
&checkbox_load_app_settings,
&checkbox_save_app_settings,
&button_save,
&button_cancel,
});
checkbox_load_app_settings.set_value(pmem::load_app_settings());
checkbox_save_app_settings.set_value(pmem::save_app_settings());
button_save.on_select = [&nav, this](Button&) {
pmem::set_load_app_settings(checkbox_load_app_settings.value());
pmem::set_save_app_settings(checkbox_save_app_settings.value());
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetAppSettingsView::focus() {
button_save.focus();
}
/* SetConverterSettingsView ******************************/
SetConverterSettingsView::SetConverterSettingsView(NavigationView& nav) {
@@ -654,7 +626,6 @@ SettingsMenuView::SettingsMenuView(NavigationView& nav) {
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
}
add_items({
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetAppSettingsView>(); }},
{"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav]() { nav.push<SetAudioView>(); }},
{"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push<TouchCalibrationView>(); }},
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetConverterSettingsView>(); }},
-35
View File
@@ -310,41 +310,6 @@ class SetUIView : public View {
};
};
class SetAppSettingsView : public View {
public:
SetAppSettingsView(NavigationView& nav);
void focus() override;
std::string title() const override { return "App Settings"; };
private:
Labels labels{
{{1 * 8, 1 * 16}, "App settings are saved to", Color::light_grey()},
{{1 * 8, 2 * 16}, "the SD card in /SETTINGS.", Color::light_grey()},
{{1 * 8, 3 * 16}, "Radio settings may also be", Color::light_grey()},
{{1 * 8, 4 * 16}, "loaded or saved per app.", Color::light_grey()},
};
Checkbox checkbox_load_app_settings{
{3 * 8, 6 * 16},
25,
"Load radio settings"};
Checkbox checkbox_save_app_settings{
{3 * 8, 8 * 16},
25,
"Save radio settings"};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
Button button_cancel{
{16 * 8, 16 * 16, 12 * 8, 32},
"Cancel",
};
};
class SetConverterSettingsView : public View {
public:
SetConverterSettingsView(NavigationView& nav);
+1
View File
@@ -51,6 +51,7 @@ class SigGenView : public View {
void on_tx_progress(const uint32_t progress, const bool done);
TxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
1536000 /* sampling rate */
};
-3
View File
@@ -66,9 +66,6 @@ SondeView::SondeView(NavigationView& nav)
&button_see_qr,
&button_see_map});
if (!settings_.radio_loaded())
field_frequency.set_value(initial_target_frequency);
field_frequency.set_step(500); // euquiq: was 10000, but we are using this for fine-tunning
geopos.set_read_only(true);
+1 -1
View File
@@ -68,6 +68,7 @@ class SondeView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
402700000 /* frequency */,
1750000 /* bandwidth */,
2457600 /* sampling rate */
};
@@ -75,7 +76,6 @@ class SondeView : public View {
"rx_sonde", app_settings::Mode::RX};
std::unique_ptr<SondeLogger> logger{};
uint32_t target_frequency_{402700000};
bool logging{false};
bool use_crc{false};
bool beep{false};
@@ -85,7 +85,11 @@ SpectrumPainterView::SpectrumPainterView(
if (tx_mode == 0 && image_input_avaliable == false)
return;
/* By experimental test measurement, we got a good painted spectrum quality when selecting
a BW GUI App range from 100k ... 2M aprox. In that range , the best TX LPF filter = 1M75 (the min)
With this min TX LPF filter , we minimized the harmonics aliasing multipicture overlapped.
So original fw 1.7.4., was already selecting the best setting (1M75) */
transmitter_model.set_baseband_bandwidth(1'750'000); // Already tested, is the best setting for this App.
transmitter_model.enable();
if (persistent_memory::stealth_mode()) {
+1
View File
@@ -160,6 +160,7 @@ void SSTVTXView::start_tx() {
scanline_counter = 0;
prepare_scanline(); // Preload one scanline
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF 1M75, same spectrum as previous fw 1.7.4
transmitter_model.enable();
baseband::set_sstv_data(
+1
View File
@@ -62,6 +62,7 @@ class TestView : public View {
private:
NavigationView& nav_;
RxRadioState radio_state_{
0 /* frequency */,
1750000 /* bandwidth */,
2457600 * 2 /* sampling rate */
};
@@ -85,7 +85,6 @@ void TouchTunesView::on_tx_progress(const uint32_t progress, const bool done) {
// transmission events.
void TouchTunesView::start_ew() {
// Radio
transmitter_model.set_target_frequency(433920000);
transmitter_model.set_rf_amp(true);
transmitter_model.set_tx_gain(47);
transmitter_model.enable();
@@ -151,10 +150,7 @@ void TouchTunesView::start_tx(const uint32_t button_index) {
size_t bitstream_length = make_bitstream(fragments);
transmitter_model.set_target_frequency(433920000);
transmitter_model.set_sampling_rate(OOK_SAMPLERATE);
transmitter_model.set_rf_amp(true);
transmitter_model.set_baseband_bandwidth(1750000);
transmitter_model.enable();
baseband::set_ook_data(
+4 -2
View File
@@ -25,6 +25,7 @@
#include "ui_transmitter.hpp"
#include "transmitter_model.hpp"
#include "radio_state.hpp"
#include "encoders.hpp"
// The coding in notpike's script is quite complex, using multiple LUTs to form the data sent to the YSO.
// The format is actually very simple if it is rather seen as short and long gaps between pulses (as seen in many OOK remotes).
@@ -115,8 +116,9 @@ class TouchTunesView : public View {
private:
TxRadioState radio_state_{
3500000 /* bandwidth */,
3072000 /* sampling rate */
433920000 /* frequency */,
1750000 /* bandwidth */,
OOK_SAMPLERATE /* sampling rate */
};
uint32_t scan_button_index{};
+38
View File
@@ -5645,6 +5645,44 @@ static constexpr Bitmap bitmap_icon_shift{
{16, 16},
bitmap_icon_shift_data};
static constexpr uint8_t bitmap_icon_trim_data[] = {
0x10,
0x10,
0x30,
0x12,
0x50,
0x15,
0x50,
0x15,
0x50,
0x15,
0x52,
0x95,
0x56,
0xD5,
0x5F,
0xF5,
0x56,
0xD5,
0x52,
0x95,
0x50,
0x15,
0x50,
0x15,
0x50,
0x15,
0x90,
0x18,
0x10,
0x10,
0x00,
0x00,
};
static constexpr Bitmap bitmap_icon_trim{
{16, 16},
bitmap_icon_trim_data};
} /* namespace ui */
#endif /*__BITMAP_HPP__*/
+7 -4
View File
@@ -57,6 +57,9 @@ uint32_t fault_address{0};
void draw_guru_meditation_header(uint8_t source, const char* hint) {
Painter painter;
// disable scroll in case a waterfall/spectrum display was active (scroll would mess up the fault display)
portapack::display.scroll_disable();
painter.fill_rectangle(
{0, 0, portapack::display.width(), portapack::display.height()},
Color::red());
@@ -134,6 +137,10 @@ void runtime_error(uint8_t source) {
led.off();
// wait for DFU button release if pressed, so we don't immediately jump into stack dump
while (swizzled_switches() & (1 << (int)Switch::Dfu))
;
while (true) {
volatile size_t n = 1000000U;
while (n--)
@@ -243,10 +250,6 @@ void draw_stack_dump() {
p = &__process_stack_base__;
break;
}
// If SEL button pressed, try writing to file (likely to hang in fault condition but heh)
if (switches & (1 << (int)Switch::Sel))
stack_dump();
}
// clear screen to allow new range to be displayed, if we're not at the end
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_calculator.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::calculator {
void initialize_app(ui::NavigationView& nav) {
nav.push<CalculatorView>();
}
} // namespace ui::external_app::calculator
extern "C" {
__attribute__((section(".external_app.app_calculator.application_information"), used)) application_information_t _application_information_calculator = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::calculator::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Calculator",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0xF8,
0x1F,
0xF8,
0x1F,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'}, // optional
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,269 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_calculator.hpp"
using namespace ui;
namespace ui::external_app::calculator {
uint8_t current_key = 255;
char display_string[10];
uint8_t fgm = 0;
// interface to external code
unsigned int mp;
char CHARMAP[] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
'H',
'I',
'L',
'M',
'N',
'O',
'P',
'R',
'S',
'T',
'U',
'V',
'c',
's',
't',
' ',
'.',
'*',
'+',
'-',
'/',
'!',
'<',
'=',
'>',
'^',
'f',
'n',
'p',
's',
'm',
'w',
};
void printcat(uint8_t c, uint8_t x) { // Print char c at position x
display_string[x] = CHARMAP[c];
}
uint8_t getkey(void) { // Read keypad
return current_key;
}
#include "ivt.hpp"
void step() {
loop();
}
void CalculatorView::focus() {
button_F.focus();
}
CalculatorView::CalculatorView(NavigationView& nav)
: nav_{nav} {
add_children({&button_F,
&button_7,
&button_8,
&button_9,
&button_E,
&button_4,
&button_5,
&button_6,
&button_N,
&button_1,
&button_2,
&button_3,
&button_C,
&button_0,
&button_P,
&button_D,
&console});
button_F.on_select = [&nav, this](Button&) { on_button_press(0); };
button_7.on_select = [&nav, this](Button&) { on_button_press(1); };
button_8.on_select = [&nav, this](Button&) { on_button_press(2); };
button_9.on_select = [&nav, this](Button&) { on_button_press(3); };
button_E.on_select = [&nav, this](Button&) { on_button_press(4); };
button_4.on_select = [&nav, this](Button&) { on_button_press(5); };
button_5.on_select = [&nav, this](Button&) { on_button_press(6); };
button_6.on_select = [&nav, this](Button&) { on_button_press(7); };
button_N.on_select = [&nav, this](Button&) { on_button_press(8); };
button_1.on_select = [&nav, this](Button&) { on_button_press(9); };
button_2.on_select = [&nav, this](Button&) { on_button_press(10); };
button_3.on_select = [&nav, this](Button&) { on_button_press(11); };
button_C.on_select = [&nav, this](Button&) { on_button_press(12); };
button_0.on_select = [&nav, this](Button&) { on_button_press(13); };
button_P.on_select = [&nav, this](Button&) { on_button_press(14); };
button_D.on_select = [&nav, this](Button&) { on_button_press(15); };
}
void CalculatorView::on_button_press(uint8_t button) {
auto pre_fgm = fgm;
for (int i = 0; i < 10; i++)
display_string[i] = ' ';
current_key = button;
step();
do {
current_key = 255;
step();
} while (mp);
std::string d(&display_string[0], 10);
if (pre_fgm && button != 0) {
console.write(" ");
switch (button) {
case 1:
console.write("SUM+");
break;
case 2:
console.write("PRG");
break;
case 3:
console.write("/");
break;
case 4:
console.write("SWAP");
break;
case 5:
console.write("DICT");
break;
case 6:
console.write("USR");
break;
case 7:
console.write("*");
break;
case 8:
console.write("ROT");
break;
case 9:
console.write("RCL");
break;
case 10:
console.write("STO");
break;
case 11:
console.write("-");
break;
case 12:
console.write("CA");
break;
case 13:
console.write("PI");
break;
case 14:
console.write("INT");
break;
case 15:
console.write("+");
break;
}
console.writeln(d);
} else if (button == 15) {
console.write("\r");
console.writeln(d);
} else {
console.write("\r");
console.write(d);
}
update_button_labels();
}
void CalculatorView::update_button_labels() {
if (fgm) {
button_F.set_text("MENU");
button_7.set_text("SUM+");
button_8.set_text("PRG");
button_9.set_text("/");
button_E.set_text("SWAP");
button_4.set_text("DICT");
button_5.set_text("USR");
button_6.set_text("*");
button_N.set_text("ROT");
button_1.set_text("RCL");
button_2.set_text("STO");
button_3.set_text("-");
button_C.set_text("CA");
button_0.set_text("PI");
button_P.set_text("INT");
button_D.set_text("+");
} else {
button_F.set_text("F");
button_7.set_text("7");
button_8.set_text("8");
button_9.set_text("9");
button_E.set_text("E");
button_4.set_text("4");
button_5.set_text("5");
button_6.set_text("6");
button_N.set_text("N");
button_1.set_text("1");
button_2.set_text("2");
button_3.set_text("3");
button_C.set_text("C");
button_0.set_text("0");
button_P.set_text(".");
button_D.set_text("D");
}
}
} // namespace ui::external_app::calculator
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_calculator_H__
#define __UI_calculator_H__
#include "ui.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_freq_field.hpp"
#include "ui_record_view.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "log_file.hpp"
#include "utility.hpp"
using namespace ui;
namespace ui::external_app::calculator {
class CalculatorView : public View {
public:
CalculatorView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Calculator"; };
private:
NavigationView& nav_;
Button button_F{{0 * 8, 11 * 16, 6 * 8, 16 + 8}, "F"};
Button button_7{{8 * 8, 11 * 16, 6 * 8, 16 + 8}, "7"};
Button button_8{{16 * 8, 11 * 16, 6 * 8, 16 + 8}, "8"};
Button button_9{{24 * 8, 11 * 16, 6 * 8, 16 + 8}, "9"};
Button button_E{{0 * 8, 13 * 16, 6 * 8, 16 + 8}, "E"};
Button button_4{{8 * 8, 13 * 16, 6 * 8, 16 + 8}, "4"};
Button button_5{{16 * 8, 13 * 16, 6 * 8, 16 + 8}, "5"};
Button button_6{{24 * 8, 13 * 16, 6 * 8, 16 + 8}, "6"};
Button button_N{{0 * 8, 15 * 16, 6 * 8, 16 + 8}, "N"};
Button button_1{{8 * 8, 15 * 16, 6 * 8, 16 + 8}, "1"};
Button button_2{{16 * 8, 15 * 16, 6 * 8, 16 + 8}, "2"};
Button button_3{{24 * 8, 15 * 16, 6 * 8, 16 + 8}, "3"};
Button button_C{{0 * 8, 17 * 16, 6 * 8, 16 + 8}, "C"};
Button button_0{{8 * 8, 17 * 16, 6 * 8, 16 + 8}, "0"};
Button button_P{{16 * 8, 17 * 16, 6 * 8, 16 + 8}, "."};
Button button_D{{24 * 8, 17 * 16, 6 * 8, 16 + 8}, "D"};
Console console{
{0 * 8, 0 * 16, screen_width, 10 * 16}};
void on_button_press(uint8_t button);
void update_button_labels();
};
} // namespace ui::external_app::calculator
#endif /*__UI_calculator_H__*/
+10
View File
@@ -7,9 +7,19 @@ set(EXTCPPSRC
#afsk_rx
external/afsk_rx/main.cpp
external/afsk_rx/ui_afsk_rx.cpp
#calculator
external/calculator/main.cpp
external/calculator/ui_calculator.cpp
#font_viewer
external/font_viewer/main.cpp
external/font_viewer/ui_font_viewer.cpp
)
set(EXTAPPLIST
pacman
afsk_rx
calculator
font_viewer
)
+18 -4
View File
@@ -17,21 +17,35 @@
MEMORY
{
/* external apps: regions can't overlap so addresses are corrected after build */
ram_external_app_pacman (rwx) : org = 0xEEE90000, len = 40k
ram_external_app_afsk_rx (rwx) : org = 0xEEEA0000, len = 40k
ram_external_app_pacman (rwx) : org = 0xEEE90000, len = 32k
ram_external_app_afsk_rx (rwx) : org = 0xEEEA0000, len = 32k
ram_external_app_calculator (rwx) : org = 0xEEEB0000, len = 32k
ram_external_app_font_viewer(rwx) : org = 0xEEEC0000, len = 32k
}
SECTIONS
{
.external_app_pacman : ALIGN(16) SUBALIGN(16)
.external_app_pacman : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_pacman.application_information));
*(*ui*external_app*pacman*);
} > ram_external_app_pacman
.external_app_afsk_rx : ALIGN(16) SUBALIGN(16)
.external_app_afsk_rx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_afsk_rx.application_information));
*(*ui*external_app*afsk_rx*);
} > ram_external_app_afsk_rx
.external_app_calculator : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_calculator.application_information));
*(*ui*external_app*calculator*);
} > ram_external_app_calculator
.external_app_font_viewer : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_font_viewer.application_information));
*(*ui*external_app*font_viewer*);
} > ram_external_app_font_viewer
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_font_viewer.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::font_viewer {
void initialize_app(ui::NavigationView& nav) {
nav.push<DebugFontsView>();
}
} // namespace ui::external_app::font_viewer
extern "C" {
__attribute__((section(".external_app.app_font_viewer.application_information"), used)) application_information_t _application_information_font_viewer = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::font_viewer::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Font Viewer",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
0x00,
0x10,
0x0C,
0x38,
0x0C,
0x38,
0x0C,
0x6C,
0x0C,
0x6C,
0x0C,
0xC6,
0x7C,
0xFE,
0xFC,
0xFF,
0x8D,
0x83,
0x8D,
0x83,
0xFD,
0x01,
0x7D,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_font_viewer.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "ui_styles.hpp"
#include "ui_painter.hpp"
#include "portapack.hpp"
using namespace portapack;
using namespace ui;
namespace ui::external_app::font_viewer {
/* DebugFontsView *******************************************************/
uint16_t DebugFontsView::display_font(Painter& painter, uint16_t y_offset, const Style* font_style, std::string_view font_name) {
auto char_width{font_style->font.char_width()};
auto char_height{font_style->font.line_height()};
auto cpl{((screen_width / char_width) - 6) & 0xF8}; // Display a multiple of 8 characters per line
uint16_t line_pos{y_offset};
painter.draw_string({0, y_offset}, *font_style, font_name);
// Displaying ASCII+extended characters from 0x20 to 0xFF
for (uint8_t c = 0; c <= 0xDF; c++) {
line_pos = y_offset + ((c / cpl) + 2) * char_height;
if ((c % cpl) == 0)
painter.draw_string({0, line_pos}, *font_style, "Ox" + to_string_hex(c + 0x20, 2));
painter.draw_char({((c % cpl) + 5) * char_width, line_pos}, *font_style, (char)(c + 0x20));
}
return line_pos + char_height;
}
void DebugFontsView::paint(Painter& painter) {
int16_t line_pos;
line_pos = display_font(painter, 32, &Styles::white, "Fixed 8x16");
display_font(painter, line_pos + 16, &Styles::white_small, "Fixed 5x8");
}
DebugFontsView::DebugFontsView(NavigationView& nav)
: nav_{nav} {
set_focusable(true);
}
} /* namespace ui::external_app::font_viewer */
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_DEBUG_H__
#define __UI_DEBUG_H__
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "ui_menu.hpp"
#include "ui_navigation.hpp"
#include <functional>
#include <utility>
using namespace ui;
namespace ui::external_app::font_viewer {
class DebugFontsView : public View {
public:
DebugFontsView(NavigationView& nav);
void paint(Painter& painter) override;
std::string title() const override { return "Fonts"; };
private:
uint16_t display_font(Painter& painter, uint16_t y_offset, const Style* font_style, std::string_view font_name);
NavigationView& nav_;
};
} /* namespace ui::external_app::font_viewer */
#endif /*__UI_FONT_VIEWER_H__*/
+8
View File
@@ -325,6 +325,14 @@ FATTimestamp file_created_date(const std::filesystem::path& file_path) {
return {filinfo.fdate, filinfo.ftime};
}
std::filesystem::filesystem_error file_update_date(const std::filesystem::path& file_path, FATTimestamp timestamp) {
FILINFO filinfo{};
filinfo.fdate = timestamp.FAT_date;
filinfo.ftime = timestamp.FAT_time;
return f_utime(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
}
std::filesystem::filesystem_error make_new_file(
const std::filesystem::path& file_path) {
File f;
+1
View File
@@ -270,6 +270,7 @@ std::filesystem::filesystem_error rename_file(const std::filesystem::path& file_
std::filesystem::filesystem_error copy_file(const std::filesystem::path& file_path, const std::filesystem::path& dest_path);
FATTimestamp file_created_date(const std::filesystem::path& file_path);
std::filesystem::filesystem_error file_update_date(const std::filesystem::path& file_path, FATTimestamp timestamp);
std::filesystem::filesystem_error make_new_file(const std::filesystem::path& file_path);
std::filesystem::filesystem_error make_new_directory(const std::filesystem::path& dir_path);
std::filesystem::filesystem_error ensure_directory(const std::filesystem::path& dir_path);
+22 -4
View File
@@ -122,7 +122,7 @@ void MAX2837::init() {
_map.r.lpf_1.LPF_EN = 1; /* Enable low-pass filter */
_map.r.lpf_1.ModeCtrl = 0b01; /* Rx LPF */
_map.r.lpf_1.FT = 0b0000; /* 5MHz LPF */
_map.r.lpf_1.FT = 0b0000; /* 1,75MHz LPF */
_map.r.spi_en.EN_SPI = 1; /* enable chip functions when ENABLE pin set */
@@ -233,10 +233,28 @@ void MAX2837::set_vga_gain(const int_fast8_t db) {
flush();
}
void MAX2837::set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) {
void MAX2837::set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) {
_map.r.lpf_1.ModeCtrl = 0b01; /* Address reg 2, D3-D2, Set mode lowpass filter block to Rx LPF . Active when Address 6 D<9> = 1 */
_map.r.lpf_1.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF_1] = 1;
flush();
flush_one(Register::LPF_1);
_map.r.vga_3_rx_top.LPF_MODE_SEL = 1; /* Address 6 reg, D9 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 2 D3:D2*/
flush_one(Register::VGA_3_RX_TOP);
_map.r.vga_3_rx_top.LPF_MODE_SEL = 0; /* Leave LPF_MODE_SEL 0 = Normal operation */
flush_one(Register::VGA_3_RX_TOP);
}
void MAX2837::set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) {
_map.r.lpf_1.ModeCtrl = 0b10; /* Address 2 reg, D3-D2, Set mode lowpass filter block to Tx LPF . Active when Address 6 D<9> = 1 */
_map.r.lpf_1.FT = filter::bandwidth_ordinal(bandwidth_minimum);
flush_one(Register::LPF_1);
_map.r.vga_3_rx_top.LPF_MODE_SEL = 1; /* Address 6 reg, D9 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 2 D3:D2*/
flush_one(Register::VGA_3_RX_TOP);
_map.r.vga_3_rx_top.LPF_MODE_SEL = 0; /* Leave LPF_MODE_SEL 0 = Normal operation */
flush_one(Register::VGA_3_RX_TOP);
}
bool MAX2837::set_frequency(const rf::Frequency lo_frequency) {
+2 -1
View File
@@ -783,7 +783,8 @@ class MAX2837 : public MAX283x {
void set_tx_vga_gain(const int_fast8_t db) override;
void set_lna_gain(const int_fast8_t db) override;
void set_vga_gain(const int_fast8_t db) override;
void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) override;
void set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) override;
void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override;
#if 0
void rx_cal() {
_map.r.spi_en.EN_SPI = 1;
+25 -3
View File
@@ -278,10 +278,32 @@ void MAX2839::set_vga_gain(const int_fast8_t db) {
configure_rx_gain();
}
void MAX2839::set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) {
void MAX2839::set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) {
_map.r.lpf_vga_1.ModeCtrl = 0b01; /* Address reg 5, D9-D8, Set mode lowpass filter block to Rx LPF . Active when Address 8 D<2> = 1 */
flush_one(Register::LPF_VGA_1);
_map.r.rx_top_1.LPF_MODE_SEL = 1; /* Address 8 reg, D2 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 5 D<9:8> */
flush_one(Register::RX_TOP_1);
_map.r.lpf.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF] = 1;
flush();
flush_one(Register::LPF);
_map.r.rx_top_1.LPF_MODE_SEL = 0; /* Address 8 reg, D2 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 5 D<9:8> */
flush_one(Register::RX_TOP_1); /* Leave LPF_MODE_SEL 0 = Normal operation */
}
void MAX2839::set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) {
_map.r.lpf_vga_1.ModeCtrl = 0b10; /* Address reg 5, D9-D8, Set mode lowpass filter block to Tx LPF . Active when Address 8 D<2> = 1 */
flush_one(Register::LPF_VGA_1);
_map.r.rx_top_1.LPF_MODE_SEL = 1; /* Address 8 reg, D2 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 5 D<9:8> */
flush_one(Register::RX_TOP_1);
_map.r.lpf.FT = filter::bandwidth_ordinal(bandwidth_minimum);
flush_one(Register::LPF);
_map.r.rx_top_1.LPF_MODE_SEL = 0; /* Address 8 reg, D2 bit:LPF mode mux, LPF_MODE_SEL 0 = Normal operation, 1 = Operating mode is programmed Address 5 D<9:8> */
flush_one(Register::RX_TOP_1); /* Leave LPF_MODE_SEL 0 = Normal operation */
}
bool MAX2839::set_frequency(const rf::Frequency lo_frequency) {
+2 -1
View File
@@ -686,7 +686,8 @@ class MAX2839 : public MAX283x {
void set_tx_vga_gain(const int_fast8_t db) override;
void set_lna_gain(const int_fast8_t db) override;
void set_vga_gain(const int_fast8_t db) override;
void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) override;
void set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) override;
void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override;
bool set_frequency(const rf::Frequency lo_frequency) override;
void set_rx_lo_iq_calibration(const size_t v) override;
void set_rx_buff_vcm(const size_t v) override;
+2 -1
View File
@@ -123,7 +123,8 @@ class MAX283x {
virtual void set_tx_vga_gain(const int_fast8_t db);
virtual void set_lna_gain(const int_fast8_t db);
virtual void set_vga_gain(const int_fast8_t db);
virtual void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum);
virtual void set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum);
virtual void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum);
virtual bool set_frequency(const rf::Frequency lo_frequency);
+8 -4
View File
@@ -92,8 +92,8 @@ max2839::MAX2839 second_if_max2839{ssp1_target_max283x};
static max5864::MAX5864 baseband_codec{ssp1_target_max5864};
static baseband::CPLD baseband_cpld;
// Set invalid to force the set_direction CPLD workaround to run.
static rf::Direction direction{-1};
// load_sram() is called at boot in portapack.cpp, including verify CPLD part, so default direction is Receive
static rf::Direction direction{rf::Direction::Receive};
static bool baseband_invert = false;
static bool mixer_invert = false;
@@ -232,8 +232,12 @@ void set_tx_gain(const int_fast8_t db) {
second_if->set_tx_vga_gain(db);
}
void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum) {
second_if->set_lpf_rf_bandwidth(bandwidth_minimum);
void set_baseband_filter_bandwidth_rx(const uint32_t bandwidth_minimum) {
second_if->set_lpf_rf_bandwidth_rx(bandwidth_minimum);
}
void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum) {
second_if->set_lpf_rf_bandwidth_tx(bandwidth_minimum);
}
void set_baseband_rate(const uint32_t rate) {
+2 -1
View File
@@ -50,7 +50,8 @@ void set_rf_amp(const bool rf_amp);
void set_lna_gain(const int_fast8_t db);
void set_vga_gain(const int_fast8_t db);
void set_tx_gain(const int_fast8_t db);
void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum);
void set_baseband_filter_bandwidth_rx(const uint32_t bandwidth_minimum);
void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum);
void set_baseband_rate(const uint32_t rate);
void set_antenna_bias(const bool on);
+6 -1
View File
@@ -41,8 +41,10 @@ class RadioState {
model->initialize();
}
RadioState(uint32_t new_bandwidth, uint32_t new_sampling_rate) {
RadioState(uint32_t new_frequency, uint32_t new_bandwidth, uint32_t new_sampling_rate) {
model->initialize();
if (new_frequency != 0)
model->set_target_frequency(new_frequency);
model->set_sampling_rate(new_sampling_rate);
model->set_baseband_bandwidth(new_bandwidth);
}
@@ -61,10 +63,13 @@ class RadioState {
typename U = TModel,
typename Mode = std::enable_if_t<sizeof(typename U::Mode), typename U::Mode> >
RadioState(
uint32_t new_frequency,
uint32_t new_bandwidth,
uint32_t new_sampling_rate,
Mode new_mode) {
model->initialize();
if (new_frequency != 0)
model->set_target_frequency(new_frequency);
model->set_sampling_rate(new_sampling_rate);
model->set_baseband_bandwidth(new_bandwidth);
model->settings().mode = new_mode;
+1 -1
View File
@@ -270,7 +270,7 @@ void ReceiverModel::update_tuning_frequency() {
}
void ReceiverModel::update_baseband_bandwidth() {
radio::set_baseband_filter_bandwidth(baseband_bandwidth());
radio::set_baseband_filter_bandwidth_rx(baseband_bandwidth());
}
void ReceiverModel::update_sampling_rate() {
+1 -1
View File
@@ -139,7 +139,7 @@ void TransmitterModel::update_tuning_frequency() {
}
void TransmitterModel::update_baseband_bandwidth() {
radio::set_baseband_filter_bandwidth(baseband_bandwidth());
radio::set_baseband_filter_bandwidth_tx(baseband_bandwidth());
}
void TransmitterModel::update_sampling_rate() {
+32 -4
View File
@@ -110,16 +110,18 @@ void BtnGridView::clear() {
void BtnGridView::add_items(std::initializer_list<GridItem> new_items) {
for (auto item : new_items) {
menu_items.push_back(item);
if (!blacklisted_app(item))
menu_items.push_back(item);
}
update_items();
}
void BtnGridView::add_item(GridItem new_item) {
menu_items.push_back(new_item);
update_items();
if (!blacklisted_app(new_item)) {
menu_items.push_back(new_item);
update_items();
}
}
void BtnGridView::update_items() {
@@ -232,4 +234,30 @@ bool BtnGridView::on_encoder(const EncoderEvent event) {
return set_highlighted(highlighted_item + event);
}
/* BlackList ******************************************************/
std::unique_ptr<char> blacklist_ptr{};
size_t blacklist_len{};
void load_blacklist() {
File f;
auto error = f.open(BLACKLIST);
if (error)
return;
blacklist_ptr = std::unique_ptr<char>(new char[f.size()]);
if (f.read(blacklist_ptr.get(), f.size()))
blacklist_len = f.size();
}
bool BtnGridView::blacklisted_app(GridItem new_item) {
std::string app_name = new_item.text;
if (blacklist_len < app_name.size())
return false;
return std::search(blacklist_ptr.get(), blacklist_ptr.get() + blacklist_len, app_name.begin(), app_name.end()) < blacklist_ptr.get() + blacklist_len;
}
} /* namespace ui */
+6
View File
@@ -36,6 +36,9 @@
#include <string>
#include <vector>
// file used for listing apps to hide from menu
#define BLACKLIST u"/SETTINGS/blacklist"
namespace ui {
struct GridItem {
@@ -47,6 +50,8 @@ struct GridItem {
// TODO: Prevent default-constructed GridItems.
};
void load_blacklist();
class BtnGridView : public View {
public:
BtnGridView(Rect new_parent_rect = {0, 0, 240, 304}, bool keep_highlight = false);
@@ -70,6 +75,7 @@ class BtnGridView : public View {
void on_blur() override;
bool on_key(const KeyEvent event) override;
bool on_encoder(const EncoderEvent event) override;
bool blacklisted_app(GridItem new_item);
private:
int rows_{3};
+9 -12
View File
@@ -149,7 +149,7 @@ bool GeoMap::on_encoder(const EncoderEvent delta) {
map_zoom++;
// Ensure that MOD(240,map_zoom)==0 for the map_zoom_line() function
if (240 % map_zoom != 0) {
if (geomap_rect_width % map_zoom != 0) {
map_zoom--;
}
} else if ((delta < 0) && (map_zoom > 1)) {
@@ -171,7 +171,7 @@ void GeoMap::map_zoom_line(ui::Color* buffer) {
// As long as MOD(width,map_zoom)==0 then we don't need to check buffer overflow case when stretching last pixel;
// For 240 width, than means no check is needed for map_zoom values up to 6
for (int i = (240 / map_zoom) - 1; i >= 0; i--) {
for (int i = (geomap_rect_width / map_zoom) - 1; i >= 0; i--) {
for (int j = 0; j < map_zoom; j++) {
buffer[(i * map_zoom) + j] = buffer[i];
}
@@ -271,24 +271,22 @@ void GeoMap::move(const float lon, const float lat) {
lon_ = lon;
lat_ = lat;
Rect map_rect = screen_rect();
// Using WGS 84/Pseudo-Mercator projection
x_pos = map_width * (lon_ + 180) / 360 - (map_rect.width() / 2);
x_pos = map_width * (lon_ + 180) / 360 - (geomap_rect_width / 2);
// Latitude calculation based on https://stackoverflow.com/a/10401734/2278659
double lat_rad = sin(lat * pi / 180);
y_pos = map_height - ((map_world_lon / 2 * log((1 + lat_rad) / (1 - lat_rad))) - map_offset) - 128; // Offset added for the GUI
// Cap position
if (x_pos > (map_width - map_rect.width()))
x_pos = map_width - map_rect.width();
if (y_pos > (map_height + map_rect.height()))
y_pos = map_height - map_rect.height();
if (x_pos > (map_width - geomap_rect_width))
x_pos = map_width - geomap_rect_width;
if (y_pos > (map_height + geomap_rect_height))
y_pos = map_height - geomap_rect_height;
// Scale calculation
float km_per_deg_lon = cos(lat * pi / 180) * 111.321; // 111.321 km/deg longitude at equator, and 0 km at poles
pixels_per_km = (map_rect.width() / 2) / km_per_deg_lon;
pixels_per_km = (geomap_rect_width / 2) / km_per_deg_lon;
}
bool GeoMap::init() {
@@ -391,11 +389,10 @@ MapMarkerStored GeoMap::store_marker(GeoMarker& marker) {
// Check if it could be on screen
// Only checking one direction to reduce CPU
const auto r = screen_rect();
double lat_rad = sin(marker.lat * pi / 180);
int x = (map_width * (marker.lon + 180) / 360) - x_pos;
int y = (map_height - ((map_world_lon / 2 * log((1 + lat_rad) / (1 - lat_rad))) - map_offset)) - y_pos; // Offset added for the GUI
if (false == ((x >= 0) && (x < r.width()) && (y > 10) && (y < r.height()))) // Dont draw within symbol size of top
if (false == ((x >= 0) && (x < geomap_rect_width) && (y > 10) && (y < geomap_rect_height))) // Dont draw within symbol size of top
{
ret = MARKER_NOT_STORED;
} else if (markerListLen < NumMarkerListElements) {
+5 -3
View File
@@ -178,6 +178,10 @@ class GeoMap : public Widget {
void clear_markers();
MapMarkerStored store_marker(GeoMarker& marker);
static const Dim banner_height = 3 * 16;
static const Dim geomap_rect_width = 240;
static const Dim geomap_rect_height = 320 - 16 - banner_height;
private:
void draw_scale(Painter& painter);
void draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color);
@@ -250,8 +254,6 @@ class GeoMapView : public View {
void setup();
const std::function<void(int32_t, float, float)> on_done{};
const Dim banner_height = 3 * 16;
GeoMapMode mode_{};
int32_t altitude_{};
GeoPos::alt_unit altitude_unit_{};
@@ -267,7 +269,7 @@ class GeoMapView : public View {
altitude_unit_};
GeoMap geomap{
{0, banner_height, 240, 320 - 16 - banner_height}};
{0, GeoMap::banner_height, GeoMap::geomap_rect_width, GeoMap::geomap_rect_height}};
Button button_ok{
{20 * 8, 8, 8 * 8, 2 * 16},
+58 -8
View File
@@ -159,6 +159,10 @@ SystemStatusView::SystemStatusView(
&status_icons,
});
rtc_battery_workaround();
ui::load_blacklist();
if (pmem::should_use_sdcard_for_pmem()) {
pmem::load_persistent_settings_from_file();
}
@@ -360,6 +364,55 @@ void SystemStatusView::on_title() {
nav_.pop();
}
void SystemStatusView::rtc_battery_workaround() {
if (sd_card::status() != sd_card::Status::Mounted)
return;
uint16_t year;
uint8_t month;
uint8_t day;
FATTimestamp timestamp;
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
// if year is 0000, assume RTC battery is dead
if (datetime.year() == 0) {
// if timestamp file is present, use it's date and add 1 day
if (std::filesystem::file_exists(DATE_FILEFLAG)) {
timestamp = file_created_date(DATE_FILEFLAG);
year = (timestamp.FAT_date >> 9) + 1980;
month = (timestamp.FAT_date >> 5) & 0xF;
day = timestamp.FAT_date & 0x1F;
// bump to next month at 28 days for simplicity
if (++day > 28) {
day = 1;
if (++month > 12) {
month = 1;
++year;
}
}
} else {
make_new_file(DATE_FILEFLAG);
year = 1980;
month = 1;
day = 1;
}
// update RTC (keeps ticking while powered on regardless of RTC battery condition)
rtc::RTC new_datetime{year, month, day, datetime.hour(), datetime.minute(), datetime.second()};
rtcSetTime(&RTCD1, &new_datetime);
// update file date
timestamp.FAT_date = ((year - 1980) << 9) | ((uint16_t)month << 5) | day;
timestamp.FAT_time = 0;
file_update_date(DATE_FILEFLAG, timestamp);
}
}
/* Information View *****************************************************/
InformationView::InformationView(
@@ -376,11 +429,8 @@ InformationView::InformationView(
&ltime});
version.set_style(&style_infobar);
ltime.set_hide_clock(pmem::hide_clock());
ltime.set_style(&style_infobar);
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(pmem::clock_with_date());
refresh();
set_dirty();
}
@@ -524,8 +574,8 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
add_items({{"..", Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
}
add_items({
{"ADS-B", ui::Color::green(), &bitmap_icon_adsb, [&nav]() { nav.push<ADSBTxView>(); }},
{"APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav]() { nav.push<APRSTXView>(); }},
{"ADS-B TX", ui::Color::green(), &bitmap_icon_adsb, [&nav]() { nav.push<ADSBTxView>(); }},
{"APRS TX", ui::Color::green(), &bitmap_icon_aprs, [&nav]() { nav.push<APRSTXView>(); }},
{"BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav]() { nav.push<BHTView>(); }},
{"BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav]() { nav.push<CoasterPagerView>(); }},
{"GPS Sim", ui::Color::green(), &bitmap_icon_gps_sim, [&nav]() { nav.push<GpsSimAppView>(); }},
@@ -535,7 +585,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
{"Morse", ui::Color::green(), &bitmap_icon_morse, [&nav]() { nav.push<MorseView>(); }},
// { "Nuoptix DTMF", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); }},
{"OOK", ui::Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push<EncodersView>(); }},
{"POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav]() { nav.push<POCSAGTXView>(); }},
{"POCSAG TX", ui::Color::green(), &bitmap_icon_pocsag, [&nav]() { nav.push<POCSAGTXView>(); }},
{"RDS", ui::Color::green(), &bitmap_icon_rds, [&nav]() { nav.push<RDSView>(); }},
{"Soundbrd", ui::Color::green(), &bitmap_icon_soundboard, [&nav]() { nav.push<SoundBoardView>(); }},
{"S.Painter", ui::Color::orange(), &bitmap_icon_paint, [&nav]() { nav.push<SpectrumPainterView>(); }},
@@ -560,7 +610,7 @@ UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
{"File Manager", Color::green(), &bitmap_icon_dir, [&nav]() { nav.push<FileManagerView>(); }},
{"Freq. Manager", Color::green(), &bitmap_icon_freqman, [&nav]() { nav.push<FrequencyManagerView>(); }},
{"Notepad", Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<TextEditorView>(); }},
{"IQ Trim", Color::orange(), &bitmap_icon_cut, [&nav]() { nav.push<IQTrimView>(); }},
{"IQ Trim", Color::orange(), &bitmap_icon_trim, [&nav]() { nav.push<IQTrimView>(); }},
{"SD Over USB", Color::yellow(), &bitmap_icon_hackrf, [&nav]() { nav.push<SdOverUsbView>(); }},
{"Signal Gen", Color::green(), &bitmap_icon_cwgen, [&nav]() { nav.push<SigGenView>(); }},
// {"Test App", Color::dark_grey(), nullptr, [&nav](){ nav.push<TestView>(); }},
+4
View File
@@ -44,6 +44,9 @@
#include <vector>
#include <utility>
// for incrementing fake date when RTC battery is dead
#define DATE_FILEFLAG u"/SETTINGS/DATE_FILEFLAG"
using namespace sd_card;
namespace ui {
@@ -235,6 +238,7 @@ class SystemStatusView : public View {
void on_title();
void refresh();
void on_clk();
void rtc_battery_workaround();
MessageHandlerRegistration message_handler_refresh{
Message::ID::StatusRefresh,
@@ -66,7 +66,7 @@ SECTIONS
PROVIDE(__fini_array_end = .);
} > flash
.text : ALIGN(16) SUBALIGN(16)
.text : ALIGN(4) SUBALIGN(4)
{
*(.text.startup.*)
*(.text)

Some files were not shown because too many files have changed in this diff Show More