mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-15 19:13:00 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 264b1b38ba | |||
| 65e71508ac | |||
| e5546159c5 | |||
| d7c961ea4f | |||
| ad987f2b5e | |||
| defb934c3f | |||
| 5a850984b9 |
@@ -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,6 +176,8 @@ GpsSimAppView::GpsSimAppView(
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(15'000'000); // GPS L1 signal use to have wide band spectrum, still with lobule energy -30dB's at + - 15 Mhz
|
||||
|
||||
if (!settings_.radio_loaded()) {
|
||||
field_frequency.set_value(initial_target_frequency);
|
||||
transmitter_model.set_sampling_rate(2600000);
|
||||
|
||||
@@ -120,6 +120,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
||||
);
|
||||
baseband::set_sample_rate(sample_rate);
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // the Minimum TX LPF 1M75 is fine.
|
||||
transmitter_model.enable();
|
||||
|
||||
tx_view.set_transmitting(true);
|
||||
|
||||
@@ -296,6 +296,10 @@ 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.set_baseband_bandwidth(6'000'000); // best settings for ADSB TX.
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_adsb();
|
||||
|
||||
@@ -57,6 +57,7 @@ void APRSTXView::start_tx() {
|
||||
// uint8_t * bb_data_ptr = shared_memory.bb_data.data;
|
||||
// text_payload.set(to_string_hex_array(bb_data_ptr + 56, 15));
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // APRS Automatic Packet Reporting System (APRS).AFSK with NBFM , max BW= 12k5 , then TX LPF min 1M75
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_afsk_data(
|
||||
|
||||
@@ -67,6 +67,7 @@ void CoasterPagerView::generate_frame() {
|
||||
void CoasterPagerView::start_tx() {
|
||||
generate_frame();
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // AFSK narrowband ,low baud, max FM dev 150khz , std 10khz. TX LPF=1M75 the min.
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_fsk_data(19 * 8, 2280000 / 1000, 5000, 32);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -187,6 +187,7 @@ void RDSView::start_tx() {
|
||||
else
|
||||
frame_datetime.clear();
|
||||
|
||||
transmitter_model.set_baseband_bandwidth(1'750'000); // Big Spectrum harmonics reduction, and now quicker decoding time.
|
||||
transmitter_model.enable();
|
||||
|
||||
tx_thread = std::make_unique<RDSThread>(frames);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
' ',
|
||||
};
|
||||
|
||||
@@ -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__*/
|
||||
|
||||
+2072
File diff suppressed because it is too large
Load Diff
@@ -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__*/
|
||||
@@ -7,9 +7,14 @@ 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
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
pacman
|
||||
afsk_rx
|
||||
calculator
|
||||
)
|
||||
|
||||
+11
-4
@@ -17,21 +17,28 @@
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -159,6 +159,8 @@ SystemStatusView::SystemStatusView(
|
||||
&status_icons,
|
||||
});
|
||||
|
||||
rtc_battery_workaround();
|
||||
|
||||
if (pmem::should_use_sdcard_for_pmem()) {
|
||||
pmem::load_persistent_settings_from_file();
|
||||
}
|
||||
@@ -360,6 +362,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 +427,8 @@ InformationView::InformationView(
|
||||
<ime});
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -560,7 +608,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>(); }},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#define _USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
#define _USE_CHMOD 0
|
||||
#define _USE_CHMOD 1
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
@@ -626,6 +626,8 @@ void Console::write(std::string message) {
|
||||
} else {
|
||||
if (c == '\n') {
|
||||
crlf();
|
||||
} else if (c == '\r') {
|
||||
pos = {0, pos.y()};
|
||||
} else if (c == '\x1B') {
|
||||
escape = true;
|
||||
} else {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 187 B |
@@ -34,7 +34,7 @@ See firmware/application/CMakeLists.txt > COMMAND ${EXPORT_EXTERNAL_APP_IMAGES}
|
||||
Usage: <command> <project source dir> <binary dir> <cmake objcopy path> <list of external image prefixes>
|
||||
"""
|
||||
|
||||
maximum_application_size = 40*1024
|
||||
maximum_application_size = 32*1024
|
||||
|
||||
if len(sys.argv) < 4:
|
||||
print(usage_message)
|
||||
@@ -124,7 +124,7 @@ for external_image_prefix in sys.argv[4:]:
|
||||
external_application_image[m4_app_offset_header_position:m4_app_offset_header_position+4] = app_image_len.to_bytes(4, byteorder='little')
|
||||
|
||||
if (len(external_application_image) > maximum_application_size) != 0:
|
||||
print("application {} can not exceed 40kb: {} bytes used".format(external_image_prefix, len(external_application_image)))
|
||||
print("application {} can not exceed 32kb: {} bytes used".format(external_image_prefix, len(external_application_image)))
|
||||
sys.exit(-1)
|
||||
|
||||
# write .ppma (portapack mayhem application)
|
||||
|
||||
Reference in New Issue
Block a user