mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-14 10:39:30 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fecfe8b8fc | |||
| dfdd52c667 | |||
| 695e6d19f4 | |||
| 6e9ecf8e7b | |||
| fd158e873a | |||
| f90bd44617 | |||
| 2602c417be | |||
| aa1264cf91 | |||
| c79abccffd | |||
| d3c9dc1f10 | |||
| 3c8335c942 | |||
| ac31f4781c | |||
| c80cae3638 | |||
| a1d7cf2b86 | |||
| 6f6d863a14 |
@@ -188,6 +188,7 @@ void copy_to_radio_model(const AppSettings& settings) {
|
||||
settings.am_config_index,
|
||||
settings.nbfm_config_index,
|
||||
settings.wfm_config_index,
|
||||
settings.wfmam_config_index,
|
||||
settings.squelch);
|
||||
}
|
||||
|
||||
@@ -218,6 +219,7 @@ void copy_from_radio_model(AppSettings& settings) {
|
||||
settings.am_config_index = receiver_model.am_configuration();
|
||||
settings.nbfm_config_index = receiver_model.nbfm_configuration();
|
||||
settings.wfm_config_index = receiver_model.wfm_configuration();
|
||||
settings.wfmam_config_index = receiver_model.wfmam_configuration();
|
||||
}
|
||||
|
||||
settings.step = receiver_model.frequency_step();
|
||||
@@ -271,6 +273,7 @@ SettingsManager::SettingsManager(
|
||||
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("wfmam_config_index"sv, &settings_.wfmam_config_index);
|
||||
bindings_.emplace_back("squelch"sv, &settings_.squelch);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ struct AppSettings {
|
||||
uint8_t am_config_index = 0;
|
||||
uint8_t nbfm_config_index = 0;
|
||||
uint8_t wfm_config_index = 0;
|
||||
uint8_t wfmam_config_index = 0;
|
||||
uint8_t squelch = 80;
|
||||
uint8_t volume;
|
||||
// NOTE: update COMMON_APP_SETTINGS_COUNT when adding to this
|
||||
|
||||
@@ -210,7 +210,7 @@ class AISAppView : public View {
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
Channel channel{
|
||||
{21 * 8, 5, 6 * 8, 4},
|
||||
|
||||
@@ -143,7 +143,7 @@ class WFMAMAptOptionsView : public View {
|
||||
};
|
||||
OptionsField options_config{
|
||||
{3 * 8, 0 * 16},
|
||||
16, // Max option char length "80khz (NOAA Apt)" example.
|
||||
16, // Max option char length "80k-NOAA Apt LPF" , example.
|
||||
{
|
||||
// Using common messages from freqman_ui.cpp
|
||||
}};
|
||||
@@ -185,7 +185,7 @@ class SPECOptionsView : public View {
|
||||
{19 * 8, 0 * 16, 11 * 8, 1 * 16}, // 18 (x col.) x char_size, 12 (length) x 8 blanking space to delete previous chars.
|
||||
"Rx_IQ_CAL "};
|
||||
NumberField field_rx_iq_phase_cal{
|
||||
{28 * 8, 0 * 16},
|
||||
{screen_width - 2 * 8, 0 * 16},
|
||||
2,
|
||||
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
|
||||
1,
|
||||
@@ -244,7 +244,7 @@ class AnalogAudioView : public View {
|
||||
{"previous_zoom"sv, &previous_zoom}, // we are saving and restoring AMFM ZOOM factor from Settings.
|
||||
}};
|
||||
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16};
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, screen_width, 1 * 16};
|
||||
const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16};
|
||||
|
||||
size_t spec_bw_index = 0;
|
||||
@@ -283,7 +283,7 @@ class AnalogAudioView : public View {
|
||||
}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
Text text_ctcss{
|
||||
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
|
||||
@@ -292,7 +292,7 @@ class AnalogAudioView : public View {
|
||||
std::unique_ptr<Widget> options_widget{};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
{0 * 8, 2 * 16, screen_width, 1 * 16},
|
||||
u"AUD",
|
||||
u"AUDIO",
|
||||
RecordView::FileType::WAV,
|
||||
|
||||
@@ -170,7 +170,7 @@ class BLECommView : public View {
|
||||
"-"};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, 240}};
|
||||
{0, 4 * 16, ui::screen_width, ui::screen_height - 80}};
|
||||
|
||||
std::string str_log{""};
|
||||
bool logging{false};
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "ui_textentry.hpp"
|
||||
#include "usb_serial_asyncmsg.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace modems;
|
||||
@@ -446,6 +447,8 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
&button_switch,
|
||||
&recent_entries_view});
|
||||
|
||||
async_tx_states_when_entered = portapack::async_tx_enabled;
|
||||
|
||||
recent_entries_view.on_select = [this](const BleRecentEntry& entry) {
|
||||
nav_.push<BleRecentEntryDetailView>(entry);
|
||||
};
|
||||
@@ -453,9 +456,9 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
check_serial_log.on_select = [this](Checkbox&, bool v) {
|
||||
serial_logging = v;
|
||||
if (v) {
|
||||
usb_serial_thread = std::make_unique<UsbSerialThread>();
|
||||
portapack::async_tx_enabled = true;
|
||||
} else {
|
||||
usb_serial_thread.reset();
|
||||
portapack::async_tx_enabled = false;
|
||||
}
|
||||
};
|
||||
check_serial_log.set_value(serial_logging);
|
||||
@@ -755,8 +758,7 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
}
|
||||
|
||||
if (serial_logging) {
|
||||
usb_serial_thread->serial_str = str_console + "\r\n";
|
||||
usb_serial_thread->str_ready = true;
|
||||
UsbSerialAsyncmsg::asyncmsg(str_console); // new line handled there, no need here.
|
||||
}
|
||||
str_console = "";
|
||||
|
||||
@@ -916,6 +918,7 @@ void BLERxView::set_parent_rect(const Rect new_parent_rect) {
|
||||
}
|
||||
|
||||
BLERxView::~BLERxView() {
|
||||
portapack::async_tx_enabled = async_tx_states_when_entered;
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -219,6 +219,7 @@ class BLERxView : public View {
|
||||
std::string filter{};
|
||||
bool logging{false};
|
||||
bool serial_logging{false};
|
||||
bool async_tx_states_when_entered{false};
|
||||
|
||||
bool name_enable{true};
|
||||
app_settings::SettingsManager settings_{
|
||||
@@ -340,18 +341,18 @@ class BLERxView : public View {
|
||||
true};
|
||||
|
||||
// Console console{
|
||||
// {0, 10 * 8, 240, 240}};
|
||||
// {0, 10 * 8, screen_height, screen_height-80}};
|
||||
|
||||
Button button_clear_list{
|
||||
{2 * 8, 320 - (16 + 32), 7 * 8, 32},
|
||||
{2 * 8, screen_height - (16 + 32), 7 * 8, 32},
|
||||
"Clear"};
|
||||
|
||||
Button button_save_list{
|
||||
{11 * 8, 320 - (16 + 32), 11 * 8, 32},
|
||||
{11 * 8, screen_height - (16 + 32), 11 * 8, 32},
|
||||
"Export CSV"};
|
||||
|
||||
Button button_switch{
|
||||
{240 - 6 * 8, 320 - (16 + 32), 4 * 8, 32},
|
||||
{screen_width - 6 * 8, screen_height - (16 + 32), 4 * 8, 32},
|
||||
"Tx"};
|
||||
|
||||
std::string str_log{""};
|
||||
|
||||
@@ -216,7 +216,7 @@ class BLETxView : public View {
|
||||
true};
|
||||
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
@@ -288,10 +288,10 @@ class BLETxView : public View {
|
||||
{{0 * 8, 9 * 16}, "Packet Data:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Console console{
|
||||
{0, 9 * 18, 240, 240}};
|
||||
{0, 9 * 18, screen_width, screen_height - 80}};
|
||||
|
||||
TextViewer dataEditView{
|
||||
{0, 9 * 18, 240, 240}};
|
||||
{0, 9 * 18, screen_width, screen_height - 80}};
|
||||
|
||||
Button button_clear_marked{
|
||||
{1 * 8, 14 * 16, 13 * 8, 3 * 8},
|
||||
|
||||
@@ -109,7 +109,7 @@ class CaptureAppView : public View {
|
||||
/*small*/ true};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
{0 * 8, 2 * 16, screen_width, 1 * 16},
|
||||
u"BBD_????.*",
|
||||
captures_dir,
|
||||
RecordView::FileType::RawS16,
|
||||
|
||||
@@ -166,7 +166,7 @@ class ERTAppView : public View {
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::ERTPacket,
|
||||
|
||||
@@ -259,7 +259,7 @@ class POCSAGAppView : public View {
|
||||
' ',
|
||||
true /*wrap*/};
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
Image image_status{
|
||||
{0 * 8 + 4, 1 * 16 + 2, 16, 16},
|
||||
|
||||
@@ -107,10 +107,10 @@ class SoundBoardView : public View {
|
||||
"<="};
|
||||
|
||||
Text page_info{
|
||||
{0, 29 * 8, 30 * 8, 16}};
|
||||
{0, 29 * 8, screen_width, 16}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 175},
|
||||
{0, 0, screen_width, 175},
|
||||
true};
|
||||
Text text_empty{
|
||||
{7 * 8, 12 * 8, 16 * 8, 16},
|
||||
@@ -131,9 +131,9 @@ class SoundBoardView : public View {
|
||||
{}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 180}};
|
||||
{screen_width - 2 * 8, 180}};
|
||||
Text text_volume_disabled{
|
||||
{28 * 8, 180, 3 * 8, 16},
|
||||
{screen_width - 2 * 8, 180, 3 * 8, 16},
|
||||
"--"};
|
||||
|
||||
Checkbox check_loop{
|
||||
@@ -147,7 +147,7 @@ class SoundBoardView : public View {
|
||||
"Random"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, 31 * 8 + 2, 30 * 8, 4}};
|
||||
{0 * 8, 31 * 8 + 2, screen_width, 4}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/*
|
||||
TODO: Now it is dyn width. There should be an algorithm to fill the menu based on it's size.
|
||||
*/
|
||||
|
||||
namespace ui {
|
||||
class AboutView : public View {
|
||||
public:
|
||||
@@ -22,11 +26,11 @@ class AboutView : public View {
|
||||
uint16_t frame_sync_count{0};
|
||||
void on_frame_sync();
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 264},
|
||||
{0, 0, screen_width, screen_height - 56},
|
||||
true};
|
||||
|
||||
Button button_ok{
|
||||
{240 / 3, 270, 240 / 3, 24},
|
||||
{screen_width / 3, screen_height - 50, screen_width / 3, 24},
|
||||
"OK",
|
||||
};
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) {
|
||||
&status_good_frame,
|
||||
&field_volume});
|
||||
|
||||
recent_entries_view.set_parent_rect({0, 16, 240, 272});
|
||||
recent_entries_view.set_parent_rect({0, 16, screen_width, 272});
|
||||
recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) {
|
||||
detail_key = entry.key();
|
||||
details_view = nav.push<ADSBRxDetailsView>(entry);
|
||||
|
||||
@@ -230,7 +230,7 @@ class ADSBRxAircraftDetailsView : public View {
|
||||
"-"};
|
||||
|
||||
Text text_model{
|
||||
{0 * 8, 6 * 16, 30 * 8, 16},
|
||||
{0 * 8, 6 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_type{
|
||||
@@ -238,19 +238,19 @@ class ADSBRxAircraftDetailsView : public View {
|
||||
"-"};
|
||||
|
||||
Text text_number_of_engines{
|
||||
{18 * 8, 8 * 16, 30 * 8, 16},
|
||||
{18 * 8, 8 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_engine_type{
|
||||
{0 * 8, 10 * 16, 30 * 8, 16},
|
||||
{0 * 8, 10 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_owner{
|
||||
{0 * 8, 12 * 16, 30 * 8, 16},
|
||||
{0 * 8, 12 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_operator{
|
||||
{0 * 8, 14 * 16, 30 * 8, 16},
|
||||
{0 * 8, 14 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Button button_close{
|
||||
@@ -312,7 +312,7 @@ class ADSBRxDetailsView : public View {
|
||||
"-"};
|
||||
|
||||
Text text_airline{
|
||||
{0 * 8, 4 * 16, 30 * 8, 16},
|
||||
{0 * 8, 4 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_country{
|
||||
@@ -320,18 +320,18 @@ class ADSBRxDetailsView : public View {
|
||||
"-"};
|
||||
|
||||
Text text_infos{
|
||||
{0 * 8, 6 * 16, 30 * 8, 16},
|
||||
{0 * 8, 6 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_info2{
|
||||
{0 * 8, 7 * 16, 30 * 8, 16},
|
||||
{0 * 8, 7 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Text text_frame_pos_even{
|
||||
{0 * 8, 14 * 16, 30 * 8, 16},
|
||||
{0 * 8, 14 * 16, screen_width, 16},
|
||||
"-"};
|
||||
Text text_frame_pos_odd{
|
||||
{0 * 8, 16 * 16, 30 * 8, 16},
|
||||
{0 * 8, 16 * 16, screen_width, 16},
|
||||
"-"};
|
||||
|
||||
Button button_aircraft_details{
|
||||
@@ -442,7 +442,7 @@ class ADSBRxView : public View {
|
||||
};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame{
|
||||
Message::ID::ADSBFrame,
|
||||
|
||||
@@ -247,8 +247,8 @@ APRSTableView::APRSTableView(NavigationView& nav, Rect parent_rec)
|
||||
|
||||
details_view.hidden(true);
|
||||
|
||||
recent_entries_view.set_parent_rect({0, 0, 240, 280});
|
||||
details_view.set_parent_rect({0, 0, 240, 280});
|
||||
recent_entries_view.set_parent_rect({0, 0, screen_width, screen_width - 40});
|
||||
details_view.set_parent_rect({0, 0, screen_width, screen_width - 40});
|
||||
|
||||
recent_entries_view.on_select = [this](const APRSRecentEntry& entry) {
|
||||
this->on_show_detail(entry);
|
||||
|
||||
@@ -134,7 +134,7 @@ class APRSDetailsView : public View {
|
||||
bool send_updates{false};
|
||||
|
||||
Console console{
|
||||
{0, 0 * 16, 240, 224}};
|
||||
{0, 0 * 16, screen_width, 224}};
|
||||
|
||||
Button button_done{
|
||||
{160, 14 * 16, 8 * 8, 3 * 16},
|
||||
@@ -220,7 +220,7 @@ class APRSRxView : public View {
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
OptionsField options_region{
|
||||
{0 * 8, 0 * 8},
|
||||
@@ -241,7 +241,7 @@ class APRSRxView : public View {
|
||||
|
||||
// DEBUG
|
||||
RecordView record_view{
|
||||
{0 * 8, 1 * 16, 30 * 8, 1 * 16},
|
||||
{0 * 8, 1 * 16, screen_width, 1 * 16},
|
||||
u"AFS_????.WAV",
|
||||
aprs_dir,
|
||||
RecordView::FileType::WAV,
|
||||
@@ -249,7 +249,7 @@ class APRSRxView : public View {
|
||||
4};
|
||||
|
||||
Console console{
|
||||
{0, 2 * 16, 240, 240}};
|
||||
{0, 2 * 16, screen_width, screen_height - 80}};
|
||||
|
||||
std::unique_ptr<APRSLogger> logger{};
|
||||
};
|
||||
@@ -265,7 +265,7 @@ class APRSRXView : public View {
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
Rect view_rect = {0, 3 * 8, 240, 280};
|
||||
Rect view_rect = {0, 3 * 8, screen_width, screen_height - 40};
|
||||
|
||||
APRSRxView view_stream{nav_, view_rect};
|
||||
APRSTableView view_table{nav_, view_rect};
|
||||
|
||||
@@ -91,7 +91,7 @@ class APRSTXView : public View {
|
||||
' '};
|
||||
|
||||
Text text_payload{
|
||||
{0 * 8, 5 * 16, 30 * 8, 16},
|
||||
{0 * 8, 5 * 16, screen_width, 16},
|
||||
"-"};
|
||||
Button button_set{
|
||||
{0 * 8, 6 * 16, 80, 32},
|
||||
|
||||
@@ -90,7 +90,7 @@ class BattinfoView : public View {
|
||||
"-"};
|
||||
|
||||
Text text_warn{
|
||||
{1 * 8, 8 * 16, 30 * 8, 2 * 16},
|
||||
{1 * 8, 8 * 16, screen_width, 2 * 16},
|
||||
""}; */
|
||||
|
||||
Button button_mode{
|
||||
|
||||
@@ -189,7 +189,7 @@ class BHTView : public View {
|
||||
|
||||
tx_modes tx_mode = IDLE;
|
||||
|
||||
Rect view_rect = {0, 3 * 8, 240, 176};
|
||||
Rect view_rect = {0, 3 * 8, screen_width, 176};
|
||||
|
||||
XylosView view_xylos{view_rect};
|
||||
EPARView view_EPAR{view_rect};
|
||||
@@ -218,7 +218,7 @@ class BHTView : public View {
|
||||
' '};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, 29 * 8, 30 * 8, 16},
|
||||
{0 * 8, 29 * 8, screen_width, 16},
|
||||
};
|
||||
|
||||
TransmitterView tx_view{
|
||||
|
||||
@@ -42,7 +42,7 @@ class BMPFileViewer : public View {
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
std::filesystem::path path_{};
|
||||
BMPViewer bmp{{0, 0, 240, 320}};
|
||||
BMPViewer bmp{{0, 0, screen_width, screen_height}};
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
@@ -78,11 +78,11 @@ class BTLERxView : public View {
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
{240 - 12 * 8, 1 * 16, 96, 24},
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
"Modem setup"};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, 240}};
|
||||
{0, 4 * 16, screen_width, screen_height - 80}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::AFSKData,
|
||||
|
||||
@@ -202,10 +202,10 @@ RegistersView::RegistersView(
|
||||
};
|
||||
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||
|
||||
registers_widget.set_parent_rect({0, 48, 240, 192});
|
||||
registers_widget.set_parent_rect({0, 48, screen_width, 192});
|
||||
registers_widget.set_page(0);
|
||||
|
||||
text_title.set_parent_rect({(240 - static_cast<int>(title.size()) * 8) / 2, 16,
|
||||
text_title.set_parent_rect({(screen_width - static_cast<int>(title.size()) * 8) / 2, 16,
|
||||
static_cast<int>(title.size()) * 8, 16});
|
||||
text_title.set(title);
|
||||
|
||||
@@ -482,7 +482,7 @@ DebugPmemView::DebugPmemView(NavigationView& nav)
|
||||
: registers_widget(RegistersWidgetConfig{CT_PMEM, PMEM_SIZE_BYTES, page_size, 8}) {
|
||||
add_children({®isters_widget, &text_checksum, &text_checksum2, &button_ok});
|
||||
|
||||
registers_widget.set_parent_rect({0, 32, 240, 192});
|
||||
registers_widget.set_parent_rect({0, 32, screen_width, 192});
|
||||
|
||||
text_checksum.set("Size: " + to_string_dec_uint(portapack::persistent_memory::data_size(), 3) + " CRC: " + to_string_hex(portapack::persistent_memory::pmem_stored_checksum(), 8));
|
||||
text_checksum2.set("Calculated CRC: " + to_string_hex(portapack::persistent_memory::pmem_calculated_checksum(), 8));
|
||||
|
||||
@@ -283,7 +283,7 @@ class DebugMemoryDumpView : public View {
|
||||
"Write"};
|
||||
|
||||
Button button_done{
|
||||
{128, 240, 96, 24},
|
||||
{128, screen_height - 80, 96, 24},
|
||||
"Done"};
|
||||
|
||||
Labels labels{
|
||||
@@ -332,7 +332,7 @@ class DebugPmemView : public View {
|
||||
Text text_checksum2{{16, 248, 208, 16}};
|
||||
|
||||
Button button_ok{
|
||||
{240 / 3, 270, 240 / 3, 24},
|
||||
{screen_width / 3, 270, screen_width / 3, 24},
|
||||
"OK",
|
||||
};
|
||||
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
|
||||
private:
|
||||
Console console {
|
||||
{ 8, 16, 224, 240 }
|
||||
{ 8, 16, 224, screen_height-80 }
|
||||
};
|
||||
|
||||
Button button_exit {
|
||||
|
||||
@@ -124,7 +124,7 @@ class EncodersConfigView : public View {
|
||||
""};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 17 * 8, 240, 32},
|
||||
{0, 17 * 8, screen_width, 32},
|
||||
waveform_buffer,
|
||||
0,
|
||||
0,
|
||||
@@ -201,7 +201,7 @@ class EncodersView : public View {
|
||||
void start_tx(const bool scan);
|
||||
void on_tx_progress(const uint32_t progress, const bool done);
|
||||
|
||||
Rect view_rect = {0, 4 * 8, 240, 168};
|
||||
Rect view_rect = {0, 4 * 8, screen_width, 168};
|
||||
|
||||
EncodersConfigView view_config{nav_, view_rect};
|
||||
EncodersScanView view_scan{nav_, view_rect};
|
||||
|
||||
@@ -84,7 +84,7 @@ class ExternalModuleView : public View {
|
||||
Text text_app5_name{{24, 160, 200, 16}};
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
SignalToken signal_token_tick_second{};
|
||||
|
||||
@@ -455,7 +455,7 @@ FileLoadView::FileLoadView(
|
||||
add_children({&menu_view});
|
||||
|
||||
// Resize menu view to fill screen
|
||||
menu_view.set_parent_rect({0, 3 * 8, 240, 29 * 8});
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, 29 * 8});
|
||||
|
||||
refresh_list();
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class FileManBaseView : public View {
|
||||
};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, 240, 26 * 8},
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
true};
|
||||
|
||||
Button button_exit{
|
||||
@@ -172,7 +172,7 @@ private:
|
||||
};
|
||||
|
||||
Text text_path {
|
||||
{ 0 * 8, 2 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 2 * 16, screen_width, 16 },
|
||||
"",
|
||||
};
|
||||
|
||||
@@ -182,7 +182,7 @@ private:
|
||||
};
|
||||
|
||||
Text text_name {
|
||||
{ 0 * 8, 7 * 16, 30 * 8, 16 },
|
||||
{ 0 * 8, 7 * 16, screen_width, 16 },
|
||||
"",
|
||||
};
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav)
|
||||
add_children({&labels,
|
||||
&menu_view});
|
||||
|
||||
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, 33 * 8});
|
||||
|
||||
ensure_directory(apps_dir);
|
||||
ensure_directory(firmware_dir);
|
||||
|
||||
@@ -60,7 +60,7 @@ class FlashUtilityView : public View {
|
||||
{{4, 4}, "Select firmware to flash:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, 240, 26 * 8},
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
true};
|
||||
|
||||
std::filesystem::path extract_tar(std::filesystem::path::string_type path, ui::Painter& painter); // extracts the tar file, and returns the firmware.bin path from it. empty string if no fw
|
||||
|
||||
@@ -100,7 +100,7 @@ class FrequencySaveView : public FreqManBaseView {
|
||||
{{0 * 8, 6 * 16}, "Description:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
TextField field_description{
|
||||
{0 * 8, 7 * 16, 30 * 8, 1 * 16},
|
||||
{0 * 8, 7 * 16, screen_width, 1 * 16},
|
||||
""};
|
||||
|
||||
Button button_save{
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace ui {
|
||||
|
||||
IQTrimView::IQTrimView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
power_buckets_.resize(screen_width);
|
||||
add_children({
|
||||
&labels,
|
||||
&field_path,
|
||||
|
||||
@@ -96,7 +96,7 @@ class IQTrimView : public View {
|
||||
|
||||
std::filesystem::path path_{};
|
||||
Optional<iq::CaptureInfo> info_{};
|
||||
std::array<iq::PowerBuckets::Bucket, screen_width> power_buckets_{};
|
||||
std::vector<iq::PowerBuckets::Bucket> power_buckets_{};
|
||||
TrimProgressUI progress_ui{};
|
||||
|
||||
Labels labels{
|
||||
@@ -112,7 +112,7 @@ class IQTrimView : public View {
|
||||
};
|
||||
|
||||
TextField field_path{
|
||||
{0 * 8, 1 * 16, 30 * 8, 1 * 16},
|
||||
{0 * 8, 1 * 16, screen_width, 1 * 16},
|
||||
"Open File..."};
|
||||
|
||||
Point pos_lines{0 * 8, 4 * 16};
|
||||
|
||||
@@ -94,10 +94,10 @@ void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint
|
||||
rf::Frequency GlassView::get_freq_from_bin_pos(uint8_t pos) {
|
||||
rf::Frequency freq_at_pos = 0;
|
||||
if (mode == LOOKING_GLASS_SINGLEPASS) {
|
||||
// starting from the middle, minus 8 ignored bin on each side. Since pos is [-120,120] after the (pos - 120), it's divided by SCREEN_W(240)/2 => 120
|
||||
freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (SCREEN_W / 2);
|
||||
// starting from the middle, minus 8 ignored bin on each side. Since pos is [-120,120] after the (pos - 120), it's divided by screen_width(240)/2 => 120
|
||||
freq_at_pos = f_center_ini + ((pos - 120) * ((looking_glass_range - ((16 * looking_glass_range) / SPEC_NB_BINS)) / 2)) / (screen_width / 2);
|
||||
} else
|
||||
freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / SCREEN_W;
|
||||
freq_at_pos = f_min + (2 * offset * each_bin_size) + (pos * looking_glass_range) / screen_width;
|
||||
return freq_at_pos;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ void GlassView::reset_live_view() {
|
||||
|
||||
// Clear screen in peak mode.
|
||||
if (live_frequency_view == 2)
|
||||
display.fill_rectangle({{0, 108 + 16}, {SCREEN_W, SCREEN_H - (108 + 16)}}, {0, 0, 0});
|
||||
display.fill_rectangle({{0, 108 + 16}, {screen_width, screen_height - (108 + 16)}}, {0, 0, 0});
|
||||
}
|
||||
|
||||
void GlassView::add_spectrum_pixel(uint8_t power) {
|
||||
@@ -130,7 +130,7 @@ void GlassView::add_spectrum_pixel(uint8_t power) {
|
||||
spectrum_data[pixel_index] = (live_frequency_integrate * spectrum_data[pixel_index] + power) / (live_frequency_integrate + 1); // smoothing
|
||||
pixel_index++;
|
||||
|
||||
if (pixel_index == SCREEN_W) // got an entire waterfall line
|
||||
if (pixel_index == screen_width) // got an entire waterfall line
|
||||
{
|
||||
if (live_frequency_view > 0) {
|
||||
constexpr int rssi_sample_range = SPEC_NB_BINS;
|
||||
@@ -140,22 +140,22 @@ void GlassView::add_spectrum_pixel(uint8_t power) {
|
||||
constexpr int raw_min = rssi_sample_range * rssi_voltage_min / adc_voltage_max;
|
||||
constexpr int raw_max = rssi_sample_range * rssi_voltage_max / adc_voltage_max;
|
||||
constexpr int raw_delta = raw_max - raw_min;
|
||||
const range_t<int> y_max_range{0, 320 - (108 + 16)};
|
||||
const range_t<int> y_max_range{0, screen_height - (108 + 16)};
|
||||
|
||||
// drawing and keeping track of max freq
|
||||
for (uint16_t xpos = 0; xpos < SCREEN_W; xpos++) {
|
||||
for (uint16_t xpos = 0; xpos < screen_width; xpos++) {
|
||||
// save max powerwull freq
|
||||
if (spectrum_data[xpos] > max_freq_power) {
|
||||
max_freq_power = spectrum_data[xpos];
|
||||
max_freq_hold = get_freq_from_bin_pos(xpos);
|
||||
}
|
||||
int16_t point = y_max_range.clip(((spectrum_data[xpos] - raw_min) * (320 - (108 + 16))) / raw_delta);
|
||||
int16_t point = y_max_range.clip(((spectrum_data[xpos] - raw_min) * (screen_height - (108 + 16))) / raw_delta);
|
||||
uint8_t color_gradient = (point * 255) / 212;
|
||||
// clear if not in peak view
|
||||
if (live_frequency_view != 2) {
|
||||
display.fill_rectangle({{xpos, 108 + 16}, {1, SCREEN_H - point}}, {0, 0, 0});
|
||||
display.fill_rectangle({{xpos, 108 + 16}, {1, screen_height - point}}, {0, 0, 0});
|
||||
}
|
||||
display.fill_rectangle({{xpos, SCREEN_H - point}, {1, point}}, {color_gradient, 0, uint8_t(255 - color_gradient)});
|
||||
display.fill_rectangle({{xpos, screen_height - point}, {1, point}}, {color_gradient, 0, uint8_t(255 - color_gradient)});
|
||||
}
|
||||
if (last_max_freq != max_freq_hold) {
|
||||
last_max_freq = max_freq_hold;
|
||||
@@ -163,7 +163,7 @@ void GlassView::add_spectrum_pixel(uint8_t power) {
|
||||
}
|
||||
plot_marker(marker_pixel_index);
|
||||
} else {
|
||||
display.draw_pixels({{0, display.scroll(1)}, {SCREEN_W, 1}}, spectrum_row); // new line at top, one less var, speedier
|
||||
display.draw_pixels({{0, display.scroll(1)}, {screen_width, 1}}, spectrum_row); // new line at top, one less var, speedier
|
||||
}
|
||||
pixel_index = 0; // Start New cascade line
|
||||
}
|
||||
@@ -199,7 +199,7 @@ bool GlassView::process_bins(uint8_t* powerlevel) {
|
||||
void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
||||
baseband::spectrum_streaming_stop();
|
||||
// Convert bins of this spectrum slice into a representative max_power and when enough, into pixels
|
||||
// we actually need SCREEN_W (240) of those bins
|
||||
// we actually need screen_width (240) of those bins
|
||||
for (uint8_t bin = 0; bin < bin_length; bin++) {
|
||||
get_max_power(spectrum, bin, max_power);
|
||||
if (max_power > range_max_power)
|
||||
@@ -238,7 +238,7 @@ void GlassView::on_hide() {
|
||||
}
|
||||
|
||||
void GlassView::on_show() {
|
||||
display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates
|
||||
display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates
|
||||
baseband::spectrum_streaming_start();
|
||||
}
|
||||
|
||||
@@ -253,11 +253,11 @@ void GlassView::on_range_changed() {
|
||||
// if the view is done in one pass, show it like in analog_audio_app
|
||||
mode = LOOKING_GLASS_SINGLEPASS;
|
||||
offset = 2;
|
||||
bin_length = SCREEN_W;
|
||||
bin_length = screen_width;
|
||||
ignore_dc = 0;
|
||||
looking_glass_bandwidth = looking_glass_range;
|
||||
looking_glass_sampling_rate = looking_glass_range;
|
||||
each_bin_size = looking_glass_bandwidth / SCREEN_W;
|
||||
each_bin_size = looking_glass_bandwidth / screen_width;
|
||||
looking_glass_step = looking_glass_bandwidth;
|
||||
f_center_ini = f_min + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
|
||||
} else {
|
||||
@@ -269,7 +269,7 @@ void GlassView::on_range_changed() {
|
||||
if (mode == LOOKING_GLASS_FASTSCAN) {
|
||||
offset = 2;
|
||||
ignore_dc = 4;
|
||||
bin_length = SCREEN_W;
|
||||
bin_length = screen_width;
|
||||
} else { // if( mode == LOOKING_GLASS_SLOWSCAN )
|
||||
offset = 2;
|
||||
bin_length = 80;
|
||||
@@ -279,7 +279,7 @@ void GlassView::on_range_changed() {
|
||||
f_center_ini = f_min - (offset * each_bin_size) + (looking_glass_bandwidth / 2); // Initial center frequency for sweep
|
||||
}
|
||||
search_span = looking_glass_range / MHZ_DIV;
|
||||
marker_pixel_step = looking_glass_range / SCREEN_W; // Each pixel value in Hz
|
||||
marker_pixel_step = looking_glass_range / screen_width; // Each pixel value in Hz
|
||||
|
||||
pixel_index = 0;
|
||||
max_power = 0;
|
||||
@@ -304,10 +304,10 @@ void GlassView::plot_marker(uint8_t pos) {
|
||||
{
|
||||
shift_y = 16;
|
||||
}
|
||||
portapack::display.fill_rectangle({0, 100 + shift_y, SCREEN_W, 8}, Theme::getInstance()->bg_darkest->background); // Clear old marker and whole marker rectangle btw
|
||||
portapack::display.fill_rectangle({pos - 2, 100 + shift_y, 5, 3}, Theme::getInstance()->fg_red->foreground); // Red marker top
|
||||
portapack::display.fill_rectangle({pos - 1, 103 + shift_y, 3, 3}, Theme::getInstance()->fg_red->foreground); // Red marker middle
|
||||
portapack::display.fill_rectangle({pos, 106 + shift_y, 1, 2}, Theme::getInstance()->fg_red->foreground); // Red marker bottom
|
||||
portapack::display.fill_rectangle({0, 100 + shift_y, screen_width, 8}, Theme::getInstance()->bg_darkest->background); // Clear old marker and whole marker rectangle btw
|
||||
portapack::display.fill_rectangle({pos - 2, 100 + shift_y, 5, 3}, Theme::getInstance()->fg_red->foreground); // Red marker top
|
||||
portapack::display.fill_rectangle({pos - 1, 103 + shift_y, 3, 3}, Theme::getInstance()->fg_red->foreground); // Red marker middle
|
||||
portapack::display.fill_rectangle({pos, 106 + shift_y, 1, 2}, Theme::getInstance()->fg_red->foreground); // Red marker bottom
|
||||
}
|
||||
|
||||
void GlassView::update_min(int32_t v) {
|
||||
@@ -358,7 +358,8 @@ GlassView::GlassView(
|
||||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wideband_spectrum);
|
||||
|
||||
spectrum_row.resize(screen_width);
|
||||
spectrum_data.resize(screen_width);
|
||||
if (!gradient.load_file(default_gradient_file)) {
|
||||
gradient.set_default();
|
||||
}
|
||||
@@ -437,11 +438,11 @@ GlassView::GlassView(
|
||||
freq_stats.hidden(true);
|
||||
button_jump.hidden(true);
|
||||
button_rst.hidden(true);
|
||||
display.scroll_set_area(109, 319); // Restart scroll on the correct coordinates.
|
||||
display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates.
|
||||
break;
|
||||
|
||||
case 1: // LEVEL
|
||||
display.fill_rectangle({{0, 108}, {SCREEN_W, 24}}, {0, 0, 0});
|
||||
display.fill_rectangle({{0, 108}, {screen_width, 24}}, {0, 0, 0});
|
||||
display.scroll_disable();
|
||||
level_integration.hidden(false);
|
||||
freq_stats.hidden(false);
|
||||
@@ -451,7 +452,7 @@ GlassView::GlassView(
|
||||
|
||||
case 2: // PEAK
|
||||
default:
|
||||
display.fill_rectangle({{0, 108}, {SCREEN_W, 24}}, {0, 0, 0});
|
||||
display.fill_rectangle({{0, 108}, {screen_width, 24}}, {0, 0, 0});
|
||||
display.scroll_disable();
|
||||
level_integration.hidden(false);
|
||||
freq_stats.hidden(false);
|
||||
@@ -491,9 +492,9 @@ GlassView::GlassView(
|
||||
|
||||
field_marker.on_encoder_change = [this](TextField&, EncoderEvent delta) {
|
||||
if ((marker_pixel_index + delta) < 0)
|
||||
marker_pixel_index = marker_pixel_index + delta + SCREEN_W;
|
||||
else if ((marker_pixel_index + delta) > SCREEN_W)
|
||||
marker_pixel_index = marker_pixel_index + delta - SCREEN_W;
|
||||
marker_pixel_index = marker_pixel_index + delta + screen_width;
|
||||
else if ((marker_pixel_index + delta) > screen_width)
|
||||
marker_pixel_index = marker_pixel_index + delta - screen_width;
|
||||
else
|
||||
marker_pixel_index = marker_pixel_index + delta;
|
||||
on_marker_change();
|
||||
@@ -531,7 +532,7 @@ GlassView::GlassView(
|
||||
};
|
||||
set_spec_iq_phase_calibration_value(get_spec_iq_phase_calibration_value()); // initialize iq_phase_calibration in radio
|
||||
|
||||
display.scroll_set_area(109, 319);
|
||||
display.scroll_set_area(109, screen_height - 1); // Restart scroll on the correct coordinates
|
||||
|
||||
// trigger:
|
||||
// Discord User jteich: WidebandSpectrum::on_message to set the trigger value. In WidebandSpectrum::execute,
|
||||
@@ -539,7 +540,7 @@ GlassView::GlassView(
|
||||
// at which time it pushes the buffer up with channel_spectrum.feed
|
||||
baseband::set_spectrum(looking_glass_bandwidth, trigger);
|
||||
|
||||
marker_pixel_index = SCREEN_W / 2;
|
||||
marker_pixel_index = screen_width / 2;
|
||||
on_range_changed(); // Force a UI update.
|
||||
|
||||
receiver_model.set_sampling_rate(looking_glass_sampling_rate); // 20mhz
|
||||
|
||||
@@ -51,9 +51,6 @@ namespace ui {
|
||||
#define LOOKING_GLASS_SINGLEPASS 2
|
||||
// one spectrum line number of bins
|
||||
#define SPEC_NB_BINS 256
|
||||
// screen dimensions
|
||||
#define SCREEN_W 240
|
||||
#define SCREEN_H 320
|
||||
|
||||
class GlassView : public View {
|
||||
public:
|
||||
@@ -155,8 +152,8 @@ class GlassView : public View {
|
||||
uint8_t min_color_power{0}; // Filter cutoff level.
|
||||
uint32_t pixel_index{0};
|
||||
|
||||
std::array<Color, SCREEN_W> spectrum_row{};
|
||||
std::array<uint8_t, SCREEN_W> spectrum_data{};
|
||||
std::vector<Color> spectrum_row{};
|
||||
std::vector<uint8_t> spectrum_data{};
|
||||
ChannelSpectrumFIFO* fifo{};
|
||||
|
||||
int32_t steps = 1;
|
||||
@@ -168,7 +165,7 @@ class GlassView : public View {
|
||||
rf::Frequency max_freq_hold = 0;
|
||||
rf::Frequency last_max_freq = 0;
|
||||
int16_t max_freq_power = -1000;
|
||||
uint8_t bin_length = SCREEN_W;
|
||||
uint8_t bin_length = screen_width;
|
||||
uint8_t offset = 0;
|
||||
uint8_t ignore_dc = 0;
|
||||
|
||||
@@ -222,7 +219,7 @@ class GlassView : public View {
|
||||
{}};
|
||||
|
||||
ButtonWithEncoder button_beep_squelch{
|
||||
{240 - 8 * 8, 2 * 16 + 4, 8 * 8, 1 * 8},
|
||||
{screen_width - 8 * 8, 2 * 16 + 4, 8 * 8, 1 * 8},
|
||||
""};
|
||||
|
||||
TextField field_marker{
|
||||
@@ -293,15 +290,15 @@ class GlassView : public View {
|
||||
}};
|
||||
|
||||
Button button_jump{
|
||||
{SCREEN_W - 4 * 8, 5 * 16, 4 * 8, 16},
|
||||
{screen_width - 4 * 8, 5 * 16, 4 * 8, 16},
|
||||
"JMP"};
|
||||
|
||||
Button button_rst{
|
||||
{SCREEN_W - 9 * 8, 5 * 16, 4 * 8, 16},
|
||||
{screen_width - 9 * 8, 5 * 16, 4 * 8, 16},
|
||||
"RST"};
|
||||
|
||||
Text freq_stats{
|
||||
{0 * 8, 5 * 16, SCREEN_W - 10 * 8, 8},
|
||||
{0 * 8, 5 * 16, screen_width - 10 * 8, 8},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_spectrum_config{
|
||||
|
||||
@@ -202,7 +202,7 @@ void MicTXView::rxaudio(bool enable) {
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
// receiver_model.set_nbfm_configuration(n); is called above, depending user's selection (8k5, 11k, 16k).
|
||||
break;
|
||||
case MIC_MOD_WFM: // WFM, BW 200Khz aprox, or the two new addional BW filters (180k, 40k)
|
||||
case MIC_MOD_WFM: // WFM, BW 200Khz aprox, or the two new addional BW filters (180k, 80k)
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
// receiver_model.set_wfm_configuration(n); is called above, depending user's selection (200k, 180k, 0k).
|
||||
@@ -300,7 +300,7 @@ void MicTXView::update_receiver_rxbw(void) {
|
||||
receiver_model.set_nbfm_configuration(rxbw_index); // we are in NFM/FM case, we need to select proper NFM/FM RX channel filter, NFM BW 8K5(0), NFM BW 11K(1), FM BW 16K (2)
|
||||
break;
|
||||
case MIC_MOD_WFM:
|
||||
receiver_model.set_wfm_configuration(rxbw_index); // we are in WFM case, we need to select proper WFB RX BW filter, WFM BW 200K(0), WFM BW 180K(1), WFM BW 40K(2)
|
||||
receiver_model.set_wfm_configuration(rxbw_index); // we are in WFM case, we need to select proper WFB RX BW filter, WFM BW 200K(0), WFM BW 180K(1), WFM BW 80K(2)
|
||||
break;
|
||||
case MIC_MOD_AM:
|
||||
receiver_model.set_am_configuration(rxbw_index); // we are in AM TX mode, we need to select proper AM full path config AM-9K filter. 0+0 =>AM-9K(0), 0+1=1 =>AM-6K(1),
|
||||
|
||||
@@ -350,7 +350,7 @@ class MicTXView : public View {
|
||||
};
|
||||
|
||||
Button tx_button{
|
||||
{10 * 8, 30 * 8, 10 * 8, 5 * 8},
|
||||
{10 * 8, screen_width, 10 * 8, 5 * 8},
|
||||
"PTT TX",
|
||||
true};
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class PlaylistView : public View {
|
||||
void handle_replay_thread_done(uint32_t return_code);
|
||||
|
||||
Text text_filename{
|
||||
{0 * 8, 0 * 16, 30 * 8, 16}};
|
||||
{0 * 8, 0 * 16, screen_width, 16}};
|
||||
|
||||
FrequencyField field_frequency{
|
||||
{0 * 8, 1 * 16}};
|
||||
@@ -139,13 +139,13 @@ class PlaylistView : public View {
|
||||
true};
|
||||
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
Text text_track{
|
||||
{0 * 8, 3 * 16, 30 * 8, 16}};
|
||||
{0 * 8, 3 * 16, screen_width, 16}};
|
||||
|
||||
NewButton button_prev{
|
||||
{2 * 8, 4 * 16, 4 * 8, 2 * 16},
|
||||
|
||||
@@ -122,10 +122,10 @@ class POCSAGTXView : public View {
|
||||
}};
|
||||
|
||||
Text text_message{
|
||||
{0 * 8, 16 * 8, 30 * 8, 16},
|
||||
{0 * 8, 16 * 8, screen_width, 16},
|
||||
""};
|
||||
Text text_message_l2{
|
||||
{0 * 8, 18 * 8, 30 * 8, 16},
|
||||
{0 * 8, 18 * 8, screen_width, 16},
|
||||
""};
|
||||
|
||||
Button button_message{
|
||||
|
||||
@@ -160,7 +160,7 @@ class RDSView : public View {
|
||||
|
||||
void start_tx();
|
||||
|
||||
Rect view_rect = {0, 8 * 8, 240, 192};
|
||||
Rect view_rect = {0, 8 * 8, screen_width, 192};
|
||||
|
||||
RDSPSNView view_PSN{nav_, view_rect};
|
||||
RDSRadioTextView view_radiotext{nav_, view_rect};
|
||||
|
||||
@@ -335,7 +335,7 @@ ReconView::ReconView(NavigationView& nav)
|
||||
tx_view.hidden(true);
|
||||
|
||||
// set record View
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, screen_width, 1 * 16},
|
||||
u"AUTO_AUDIO", audio_dir,
|
||||
RecordView::FileType::WAV, 4096, 4);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
@@ -1164,18 +1164,18 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
|
||||
}
|
||||
if (new_mod == SPEC_MODULATION) {
|
||||
if (persistent_memory::recon_repeat_recorded()) {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, screen_width, 1 * 16},
|
||||
u"RECON_REPEAT.C16", captures_dir,
|
||||
RecordView::FileType::RawS16, 16384, 3);
|
||||
record_view->set_filename_as_is(true);
|
||||
} else {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, screen_width, 1 * 16},
|
||||
u"AUTO_RAW", captures_dir,
|
||||
RecordView::FileType::RawS16, 16384, 3);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
}
|
||||
} else {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, screen_width, 1 * 16},
|
||||
u"AUTO_AUDIO", audio_dir,
|
||||
RecordView::FileType::WAV, 4096, 4);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
@@ -1404,8 +1404,8 @@ void ReconView::start_repeat() {
|
||||
std::string delay_message = "TX DELAY: " + to_string_dec_uint(delay) + "s";
|
||||
|
||||
// update display information
|
||||
p.fill_rectangle({0, (SCREEN_H / 2) - 16, SCREEN_W, 64}, Theme::getInstance()->fg_light->foreground);
|
||||
p.draw_string({(SCREEN_W / 2) - 7 * 8, SCREEN_H / 2}, *Theme::getInstance()->fg_red, delay_message);
|
||||
p.fill_rectangle({0, (screen_height / 2) - 16, screen_width, 64}, Theme::getInstance()->fg_light->foreground);
|
||||
p.draw_string({(screen_width / 2) - 7 * 8, screen_height / 2}, *Theme::getInstance()->fg_red, delay_message);
|
||||
|
||||
// sleep 1 second
|
||||
chThdSleepMilliseconds(1000);
|
||||
|
||||
@@ -237,15 +237,15 @@ class ReconView : public View {
|
||||
|
||||
Text file_name{
|
||||
// show file used
|
||||
{0, 1 * 16, SCREEN_W, 16},
|
||||
{0, 1 * 16, screen_width, 16},
|
||||
};
|
||||
|
||||
Text desc_cycle{
|
||||
{0, 2 * 16, SCREEN_W, 16},
|
||||
{0, 2 * 16, screen_width, 16},
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
{0 * 16, 3 * 16 + 2, SCREEN_W - 8 * 8 + 4, 12},
|
||||
{0 * 16, 3 * 16 + 2, screen_width - 8 * 8 + 4, 12},
|
||||
};
|
||||
|
||||
ButtonWithEncoder text_cycle{
|
||||
@@ -285,15 +285,15 @@ class ReconView : public View {
|
||||
|
||||
// Button can be RECON or SCANNER
|
||||
Button button_scanner_mode{
|
||||
{SCREEN_W - 7 * 8, 3 * 16, 7 * 8, 28},
|
||||
{screen_width - 7 * 8, 3 * 16, 7 * 8, 28},
|
||||
"RECON"};
|
||||
|
||||
Button button_loop_config{
|
||||
{SCREEN_W - 7 * 8, 5 * 16, 7 * 8, 28},
|
||||
{screen_width - 7 * 8, 5 * 16, 7 * 8, 28},
|
||||
"[LOOP]"};
|
||||
|
||||
Button button_config{
|
||||
{SCREEN_W - 7 * 8, 7 * 16, 7 * 8, 28},
|
||||
{screen_width - 7 * 8, 7 * 16, 7 * 8, 28},
|
||||
"CONFIG"};
|
||||
|
||||
ButtonWithEncoder button_manual_start{
|
||||
@@ -391,7 +391,7 @@ class ReconView : public View {
|
||||
"<REMOVE>"};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0 * 8, SCREEN_H / 2 - 16, SCREEN_W, 32}};
|
||||
{0 * 8, screen_height / 2 - 16, screen_width, 32}};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
{11 * 8, 2 * 16},
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
#define RECON_MIN_LOCK_DURATION 100 // have to be >= and a multiple of STATS_UPDATE_INTERVAL
|
||||
#define RECON_DEF_WAIT_DURATION 1000 // will be incremented/decremented by STATS_UPDATE_INTERVAL steps
|
||||
|
||||
// screen size helper
|
||||
#define SCREEN_W 240
|
||||
// #define SCREEN_H 320
|
||||
|
||||
// recon settings nb params
|
||||
#define RECON_SETTINGS_NB_PARAMS 7
|
||||
|
||||
@@ -219,7 +215,7 @@ class ReconSetupView : public View {
|
||||
std::string input_file{"RECON"};
|
||||
std::string output_file{"RECON_RESULTS"};
|
||||
|
||||
Rect view_rect{0, 3 * 8, SCREEN_W, 230};
|
||||
Rect view_rect{0, 3 * 8, screen_width, 230};
|
||||
|
||||
ReconSetupViewMain viewMain{nav_, view_rect, input_file, output_file};
|
||||
ReconSetupViewMore viewMore{nav_, view_rect};
|
||||
|
||||
@@ -759,7 +759,7 @@ AppSettingsView::AppSettingsView(
|
||||
add_children({&labels,
|
||||
&menu_view});
|
||||
|
||||
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
|
||||
menu_view.set_parent_rect({0, 3 * 8, screen_width, 33 * 8});
|
||||
|
||||
ensure_directory(settings_dir);
|
||||
|
||||
|
||||
@@ -713,7 +713,7 @@ class AppSettingsView : public View {
|
||||
{{0, 4}, "Select file to edit:", Theme::getInstance()->bg_darkest->foreground}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, 240, 26 * 8},
|
||||
{0, 2 * 8, screen_width, 26 * 8},
|
||||
true};
|
||||
};
|
||||
|
||||
@@ -947,7 +947,7 @@ class SetThemeView : public View {
|
||||
|
||||
OptionsField options{
|
||||
{0 * 8, 4 * 16},
|
||||
screen_width / 8,
|
||||
(size_t)(screen_width / 8),
|
||||
{
|
||||
{"Default - Grey", 0},
|
||||
{"Yellow", 1},
|
||||
|
||||
@@ -57,7 +57,7 @@ void SIGFRXView::paint(Painter& painter) {
|
||||
uint8_t i, xp;
|
||||
|
||||
// portapack::display.draw_bmp_from_bmp_hex_arr({0, 302-160}, fox_bmp);
|
||||
portapack::display.fill_rectangle({0, 16, 240, 160 - 16}, Theme::getInstance()->bg_darkest->foreground);
|
||||
portapack::display.fill_rectangle({0, 16, screen_width, 160 - 16}, Theme::getInstance()->bg_darkest->foreground);
|
||||
for (i = 0; i < 6; i++) {
|
||||
xp = sigfrx_marks[i * 3];
|
||||
painter.draw_string({(ui::Coord)sigfrx_marks[(i * 3) + 1], 144 - 20}, style_white, to_string_dec_uint(sigfrx_marks[(i * 3) + 2]));
|
||||
@@ -66,7 +66,7 @@ void SIGFRXView::paint(Painter& painter) {
|
||||
}
|
||||
|
||||
void SIGFRXView::on_channel_spectrum(const ChannelSpectrum& spectrum) {
|
||||
portapack::display.fill_rectangle({0, 144, 240, 4}, Theme::getInstance()->bg_darkest->foreground);
|
||||
portapack::display.fill_rectangle({0, 144, screen_width, 4}, Theme::getInstance()->bg_darkest->foreground);
|
||||
|
||||
uint8_t xmax = 0, imax = 0;
|
||||
size_t i;
|
||||
|
||||
@@ -120,7 +120,7 @@ class SondeView : public View {
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
Checkbox check_log{
|
||||
{22 * 8, 8 * 16},
|
||||
|
||||
@@ -58,7 +58,7 @@ void ScreenshotViewer::paint(Painter& painter) {
|
||||
}
|
||||
|
||||
// Screenshots from PNGWriter are all this size.
|
||||
if (file.size() != 232383) {
|
||||
if ((file.size() != 232383 && screen_width == 240) || (screen_width == 320 && file.size() != 463743)) {
|
||||
show_invalid();
|
||||
return;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ void ScreenshotViewer::paint(Painter& painter) {
|
||||
constexpr size_t read_chunk = 80; // NB: must be a factor of pixel_width.
|
||||
constexpr size_t buffer_size = sizeof(ColorRGB888) * read_chunk;
|
||||
uint8_t buffer[buffer_size];
|
||||
std::array<Color, screen_width> pixel_data;
|
||||
std::vector<Color> pixel_data(screen_width);
|
||||
|
||||
// Seek past all the headers.
|
||||
file.seek(43);
|
||||
|
||||
@@ -192,7 +192,7 @@ class SubGhzDRecentEntryDetailView : public View {
|
||||
Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, screen_height - (4 * 16) - 36}};
|
||||
{0, 4 * 16, screen_width, screen_height - (4 * 16) - 36}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Type:", Theme::getInstance()->fg_light->foreground},
|
||||
|
||||
@@ -99,8 +99,8 @@ void TestView::on_packet(const testapp::Packet& packet) {
|
||||
display.draw_pixel(Point(cur_x, 4 * 16 + (256 - ((raw_alt - cal_value) / 4))), Color::white());
|
||||
|
||||
cur_x++;
|
||||
if (cur_x >= 240) {
|
||||
display.fill_rectangle(Rect(0, 5 * 16, 240, 256), Color::black());
|
||||
if (cur_x >= screen_width) {
|
||||
display.fill_rectangle(Rect(0, 5 * 16, screen_width, 256), Color::black());
|
||||
cur_x = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,10 +95,10 @@ class TestView : public View {
|
||||
};
|
||||
|
||||
Text text_debug_a{
|
||||
{0 * 8, 4 * 16, 30 * 8, 16},
|
||||
{0 * 8, 4 * 16, screen_width, 16},
|
||||
"..."};
|
||||
Text text_debug_b{
|
||||
{0 * 8, 5 * 16, 30 * 8, 16},
|
||||
{0 * 8, 5 * 16, screen_width, 16},
|
||||
"..."};
|
||||
|
||||
Button button_cal{
|
||||
|
||||
@@ -149,7 +149,7 @@ class WeatherView : public View {
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
|
||||
@@ -93,8 +93,8 @@ void NBFMConfig::apply(const uint8_t squelch_level) const {
|
||||
|
||||
void WFMConfig::apply() const {
|
||||
const WFMConfigureMessage message{
|
||||
decim_0, // Dynamic array 24 taps : taps_200k_decim_0 , taps_180k_wfm_decim_0, taps_40k_wfm_decim_0
|
||||
decim_1, // Dynamic array 16 taps : taps_200k_decim_1 or taps_180k_wfm_decim_1, taps_40k_wfm_decim_1
|
||||
decim_0, // Dynamic array 24 taps : taps_200k_decim_0 , taps_180k_wfm_decim_0, taps_80k_wfm_decim_0
|
||||
decim_1, // Dynamic array 16 taps : taps_200k_decim_1 or taps_180k_wfm_decim_1, taps_80k_wfm_decim_1
|
||||
taps_64_lp_156_198, // Fixed channel audio filter 15khz
|
||||
75000,
|
||||
audio_48k_hpf_30hz_config,
|
||||
@@ -105,10 +105,10 @@ void WFMConfig::apply() const {
|
||||
|
||||
void WFMAMConfig::apply() const {
|
||||
const WFMAMConfigureMessage message{
|
||||
decim_0, // Fixed 24 taps array : taps_16k0_decim_0
|
||||
decim_1, // Fixed 32 taps array : taps_84k_wfm_decim_1
|
||||
taps_64_lp_1875_2166, // Fixed channel audio filter , 64 taps array , to filter DSB AM 2k4 carrier before demod. AM .
|
||||
17000, // NOAA satellite tx , FM deviation = +-17Khz.
|
||||
decim_0, // Fixed 24 taps array : taps_16k0_decim_0
|
||||
decim_1, // Dynamic 32 taps array : taps_80k_wfmam_decim_1, 38k_wfmam
|
||||
taps_64_lp_bpf, // Dynamic 64 taps array , to filter modulated DSB AM 2k4 carrier before demod. AM .(LPF / BPF)
|
||||
17000, // NOAA satellite tx , FM deviation = +-17Khz.
|
||||
apt_audio_12k_notch_2k4_config,
|
||||
apt_audio_12k_lpf_2000hz_config};
|
||||
send_message(&message);
|
||||
|
||||
@@ -56,7 +56,7 @@ struct NBFMConfig {
|
||||
};
|
||||
|
||||
struct WFMConfig {
|
||||
const fir_taps_real<24> decim_0; // To handle all 3 WFM filters , 200k, 180k and 40K-
|
||||
const fir_taps_real<24> decim_0; // To handle all 3 WFM filters , 200k, 180k and 80K-
|
||||
const fir_taps_real<16> decim_1;
|
||||
|
||||
void apply() const;
|
||||
@@ -65,6 +65,7 @@ struct WFMConfig {
|
||||
struct WFMAMConfig {
|
||||
const fir_taps_real<24> decim_0; // To handle WFM filter BW=40K for NOAA APT
|
||||
const fir_taps_real<32> decim_1;
|
||||
const fir_taps_real<64> taps_64_lp_bpf; // to handle dynamically LPF / BPF .
|
||||
|
||||
void apply() const;
|
||||
};
|
||||
|
||||
+2
-2
@@ -87,10 +87,10 @@ class ACARSAppView : public View {
|
||||
true};
|
||||
|
||||
Console console{
|
||||
{0, 3 * 16, 240, 256}};
|
||||
{0, 3 * 16, screen_width, 256}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 1 * 16}};
|
||||
{screen_width - 2 * 8, 1 * 16}};
|
||||
|
||||
std::unique_ptr<ACARSLogger> logger{};
|
||||
|
||||
|
||||
+1
-1
@@ -218,7 +218,7 @@ class ADSBTxView : public View {
|
||||
void start_tx();
|
||||
void generate_frames();
|
||||
|
||||
Rect view_rect = {0, 7 * 8, 240, 192};
|
||||
Rect view_rect = {0, 7 * 8, screen_width, 192};
|
||||
|
||||
ADSBPositionView view_position{nav_, view_rect};
|
||||
ADSBCallsignView view_callsign{nav_, view_rect};
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ class AFSKRxView : public View {
|
||||
{21 * 8, 5, 6 * 8, 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
@@ -105,7 +105,7 @@ class AFSKRxView : public View {
|
||||
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, screen_width}};
|
||||
{0, 4 * 16, screen_width, screen_width}};
|
||||
|
||||
void on_data_afsk(const AFSKDataMessage& message);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class AnalogTvView : public View {
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_tv", app_settings::Mode::RX};
|
||||
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16};
|
||||
const Rect options_view_rect{0 * 8, 1 * 16, screen_width, 1 * 16};
|
||||
const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16};
|
||||
|
||||
RSSI rssi{
|
||||
|
||||
@@ -86,7 +86,7 @@ class WhipCalcView : public View {
|
||||
{13 * 8, 4 * 16, 10 * 16, 16},
|
||||
"-"};
|
||||
Console console{
|
||||
{0, 6 * 16, 240, 160}};
|
||||
{0, 6 * 16, screen_width, 160}};
|
||||
|
||||
Button button_exit{
|
||||
{72, 17 * 16, 96, 32},
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ class BLESpamView : public View {
|
||||
|
||||
#ifdef BLESPMUSECONSOLE
|
||||
Console console{
|
||||
{0, 70, 240, 220}};
|
||||
{0, 70, screen_width, 220}};
|
||||
#endif
|
||||
OptionsField options_atkmode{
|
||||
{0 * 8, 2 * 8},
|
||||
|
||||
+12
-10
@@ -12,8 +12,8 @@ namespace ui::external_app::breakout {
|
||||
|
||||
Ticker game_timer;
|
||||
|
||||
int paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2;
|
||||
float ball_x = SCREEN_WIDTH / 2;
|
||||
int paddle_x = 0;
|
||||
float ball_x = 0;
|
||||
float ball_y = GAME_AREA_BOTTOM - PADDLE_HEIGHT - BALL_SIZE - 1;
|
||||
float ball_dx = 1.5f;
|
||||
float ball_dy = -2.0f;
|
||||
@@ -105,7 +105,7 @@ void game_timer_check() {
|
||||
}
|
||||
|
||||
void init_game() {
|
||||
paddle_x = (SCREEN_WIDTH - PADDLE_WIDTH) / 2;
|
||||
paddle_x = (screen_width - PADDLE_WIDTH) / 2;
|
||||
score = 0;
|
||||
lives = 3;
|
||||
level = 1;
|
||||
@@ -157,7 +157,7 @@ void draw_screen() {
|
||||
}
|
||||
|
||||
void draw_borders() {
|
||||
rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER);
|
||||
rect(0, GAME_AREA_TOP - 1, screen_width, GAME_AREA_TOP, COLOR_BORDER);
|
||||
}
|
||||
|
||||
void draw_bricks() {
|
||||
@@ -218,14 +218,14 @@ void move_paddle_left() {
|
||||
}
|
||||
|
||||
void move_paddle_right() {
|
||||
if (paddle_x < SCREEN_WIDTH - PADDLE_WIDTH) {
|
||||
if (paddle_x < screen_width - PADDLE_WIDTH) {
|
||||
fillrect(paddle_x, PADDLE_Y, paddle_x + PADDLE_WIDTH, PADDLE_Y + PADDLE_HEIGHT, COLOR_BACKGROUND);
|
||||
if (ball_attached) {
|
||||
fillrect(ball_x, ball_y, ball_x + BALL_SIZE, ball_y + BALL_SIZE, COLOR_BACKGROUND);
|
||||
}
|
||||
|
||||
paddle_x += 10;
|
||||
if (paddle_x > SCREEN_WIDTH - PADDLE_WIDTH) paddle_x = SCREEN_WIDTH - PADDLE_WIDTH;
|
||||
if (paddle_x > screen_width - PADDLE_WIDTH) paddle_x = screen_width - PADDLE_WIDTH;
|
||||
|
||||
if (ball_attached) {
|
||||
ball_x = paddle_x + (PADDLE_WIDTH / 2) - (BALL_SIZE / 2);
|
||||
@@ -277,8 +277,8 @@ void update_game() {
|
||||
if (ball_x < 0) {
|
||||
ball_x = 0;
|
||||
ball_dx = -ball_dx;
|
||||
} else if (ball_x > SCREEN_WIDTH - BALL_SIZE) {
|
||||
ball_x = SCREEN_WIDTH - BALL_SIZE;
|
||||
} else if (ball_x > screen_width - BALL_SIZE) {
|
||||
ball_x = screen_width - BALL_SIZE;
|
||||
ball_dx = -ball_dx;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ void init_menu() {
|
||||
auto style_blue = *ui::Theme::getInstance()->fg_blue;
|
||||
auto style_cyan = *ui::Theme::getInstance()->fg_cyan;
|
||||
|
||||
int16_t screen_width = 240;
|
||||
int16_t screen_width = ui::screen_width;
|
||||
int16_t title_x = (screen_width - 17 * 8) / 2;
|
||||
int16_t divider_width = 24 * 8;
|
||||
int16_t divider_x = (screen_width - divider_width) / 2;
|
||||
@@ -428,7 +428,7 @@ void init_game_over() {
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
|
||||
int16_t screen_width = 240;
|
||||
// int16_t screen_width = screen_width;
|
||||
int16_t title_width = 9 * 8;
|
||||
int16_t title_x = (screen_width - title_width) / 2;
|
||||
int16_t score_text_width = (16 + std::to_string(score).length()) * 8;
|
||||
@@ -484,6 +484,8 @@ void reset_game() {
|
||||
|
||||
BreakoutView::BreakoutView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
paddle_x = (screen_width - PADDLE_WIDTH) / 2;
|
||||
ball_x = screen_width / 2;
|
||||
add_children({&dummy});
|
||||
game_timer.attach(&game_timer_check, 1.0 / 60.0);
|
||||
}
|
||||
|
||||
+1
-3
@@ -56,8 +56,6 @@ class Ticker {
|
||||
void detach();
|
||||
};
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 320
|
||||
#define PADDLE_WIDTH 40
|
||||
#define PADDLE_HEIGHT 10
|
||||
#define BALL_SIZE 8
|
||||
@@ -141,7 +139,7 @@ class BreakoutView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ class CVSSpamView : public View {
|
||||
std::vector<std::filesystem::path> file_list{};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 180},
|
||||
{0, 0, screen_width, 180},
|
||||
true};
|
||||
|
||||
Text text_empty{
|
||||
@@ -84,7 +84,7 @@ class CVSSpamView : public View {
|
||||
LanguageHelper::currentMessages[LANG_STOP]};
|
||||
|
||||
ProgressBar progressbar{
|
||||
{0, 256, 240, 44}};
|
||||
{0, 256, screen_width, 44}};
|
||||
|
||||
MessageHandlerRegistration message_handler_fifo_signal{
|
||||
Message::ID::RequestSignal,
|
||||
|
||||
@@ -44,7 +44,7 @@ class DebugDumpView : public View {
|
||||
NavigationView& nav_;
|
||||
|
||||
Text dump_output{
|
||||
{0 * 8, 19 * 8, 30 * 8, 16},
|
||||
{0 * 8, 19 * 8, screen_width, 16},
|
||||
""};
|
||||
|
||||
Button button_exit{
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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_detector_rx.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::detector_rx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<DetectorRxView>();
|
||||
}
|
||||
} // namespace ui::external_app::detector_rx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_detector_rx.application_information"), used)) application_information_t _application_information_detector_rx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::detector_rx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Detector",
|
||||
/*.bitmap_data = */
|
||||
{
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x04,
|
||||
0x20,
|
||||
0x12,
|
||||
0x48,
|
||||
0x8A,
|
||||
0x51,
|
||||
0xCA,
|
||||
0x53,
|
||||
0xCA,
|
||||
0x53,
|
||||
0x8A,
|
||||
0x51,
|
||||
0x12,
|
||||
0x48,
|
||||
0x84,
|
||||
0x21,
|
||||
0xC0,
|
||||
0x03,
|
||||
0x40,
|
||||
0x02,
|
||||
0x60,
|
||||
0x06,
|
||||
0x20,
|
||||
0x04,
|
||||
0x30,
|
||||
0x0C,
|
||||
0xF0,
|
||||
0x0F},
|
||||
/*.icon_color = */ ui::Color::orange().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
// this has to be the biggest baseband used by the app. SPEC
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_nfm */ {'P', 'W', 'F', 'M'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
||||
*
|
||||
* 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_detector_rx.hpp"
|
||||
#include "ui_fileman.hpp"
|
||||
#include "ui_freqman.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "file.hpp"
|
||||
#include "oversample.hpp"
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace tonekey;
|
||||
using portapack::memory::map::backup_ram;
|
||||
|
||||
namespace ui::external_app::detector_rx {
|
||||
|
||||
// Function to map the value from one range to another
|
||||
int32_t DetectorRxView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) {
|
||||
return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow);
|
||||
}
|
||||
|
||||
void DetectorRxView::focus() {
|
||||
field_lna.focus();
|
||||
}
|
||||
|
||||
DetectorRxView::~DetectorRxView() {
|
||||
// reset performance counters request to default
|
||||
shared_memory.request_m4_performance_counter = 0;
|
||||
receiver_model.disable();
|
||||
audio::output::stop();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
void DetectorRxView::on_timer() {
|
||||
freq_index++;
|
||||
if (freq_mode == 0 && freq_index >= tetra_uplink_monitoring_frequencies_hz.size()) freq_index = 0; // TETRA UP
|
||||
if (freq_mode == 1 && freq_index >= lora_monitoring_frequencies_hz.size()) freq_index = 0; // Lora
|
||||
if (freq_mode == 2 && freq_index >= remotes_monitoring_frequencies_hz.size()) freq_index = 0; // Remotes
|
||||
|
||||
if (freq_mode == 2)
|
||||
freq_ = remotes_monitoring_frequencies_hz[freq_index];
|
||||
else if (freq_mode == 1)
|
||||
freq_ = lora_monitoring_frequencies_hz[freq_index];
|
||||
else
|
||||
freq_ = tetra_uplink_monitoring_frequencies_hz[freq_index];
|
||||
receiver_model.set_target_frequency(freq_);
|
||||
}
|
||||
|
||||
DetectorRxView::DetectorRxView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children({
|
||||
&labels,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_rf_amp,
|
||||
&field_volume,
|
||||
&text_frequency,
|
||||
&freq_stats_rssi,
|
||||
&freq_stats_db,
|
||||
&text_beep_squelch,
|
||||
&field_beep_squelch,
|
||||
&rssi,
|
||||
&rssi_graph,
|
||||
&field_mode,
|
||||
});
|
||||
|
||||
// activate vertical bar mode
|
||||
rssi.set_vertical_rssi(true);
|
||||
|
||||
freq_ = receiver_model.target_frequency();
|
||||
|
||||
field_beep_squelch.set_value(beep_squelch);
|
||||
field_beep_squelch.on_change = [this](int32_t v) {
|
||||
beep_squelch = v;
|
||||
};
|
||||
|
||||
rssi_graph.set_nb_columns(256);
|
||||
|
||||
change_mode();
|
||||
rssi.set_peak(true, 3000);
|
||||
|
||||
// FILL STEP OPTIONS
|
||||
freq_stats_rssi.set_style(Theme::getInstance()->bg_darkest);
|
||||
freq_stats_db.set_style(Theme::getInstance()->bg_darkest);
|
||||
|
||||
field_mode.on_change = [this](size_t, int32_t value) {
|
||||
freq_mode = value;
|
||||
freq_index = 0;
|
||||
switch (value) {
|
||||
case 1: // Lora
|
||||
text_frequency.set(" 433, 868, 915 Mhz");
|
||||
break;
|
||||
case 2: // Remotes
|
||||
text_frequency.set(" 433, 315 Mhz");
|
||||
break;
|
||||
default:
|
||||
case 0: // TETRA UP
|
||||
text_frequency.set(" 380-390 Mhz");
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void DetectorRxView::on_statistics_update(const ChannelStatistics& statistics) {
|
||||
static int16_t last_max_db = 0;
|
||||
static uint8_t last_min_rssi = 0;
|
||||
static uint8_t last_avg_rssi = 0;
|
||||
static uint8_t last_max_rssi = 0;
|
||||
|
||||
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
|
||||
|
||||
// refresh db
|
||||
if (last_max_db != statistics.max_db) {
|
||||
last_max_db = statistics.max_db;
|
||||
freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db");
|
||||
rssi.set_db(statistics.max_db);
|
||||
}
|
||||
// refresh rssi
|
||||
if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) {
|
||||
last_min_rssi = rssi_graph.get_graph_min();
|
||||
last_avg_rssi = rssi_graph.get_graph_avg();
|
||||
last_max_rssi = rssi_graph.get_graph_max();
|
||||
freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi));
|
||||
}
|
||||
|
||||
if (statistics.max_db > beep_squelch) {
|
||||
baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150);
|
||||
}
|
||||
|
||||
} /* on_statistic_updates */
|
||||
|
||||
size_t DetectorRxView::change_mode() {
|
||||
audio::output::stop();
|
||||
receiver_model.disable();
|
||||
baseband::shutdown();
|
||||
|
||||
audio_sampling_rate = audio::Rate::Hz_24000;
|
||||
baseband::run_image(portapack::spi_flash::image_tag_capture);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
|
||||
|
||||
baseband::set_sample_rate(DETECTOR_BW, get_oversample_rate(DETECTOR_BW));
|
||||
// The radio needs to know the effective sampling rate.
|
||||
auto actual_sampling_rate = get_actual_sample_rate(DETECTOR_BW);
|
||||
receiver_model.set_sampling_rate(actual_sampling_rate);
|
||||
receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate));
|
||||
|
||||
audio::set_rate(audio_sampling_rate);
|
||||
audio::output::start();
|
||||
receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack.
|
||||
|
||||
receiver_model.enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::detector_rx
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
||||
*
|
||||
* 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_DETECTOR_RX
|
||||
#define _UI_DETECTOR_RX
|
||||
|
||||
#include "analog_audio_app.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "file.hpp"
|
||||
#include "freqman_db.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "receiver_model.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "ui_mictx.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
|
||||
namespace ui::external_app::detector_rx {
|
||||
|
||||
#define DETECTOR_BW 750000
|
||||
|
||||
class DetectorRxView : public View {
|
||||
public:
|
||||
DetectorRxView(NavigationView& nav);
|
||||
~DetectorRxView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "Detector RX"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
RxRadioState radio_state_{};
|
||||
|
||||
int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh);
|
||||
size_t change_mode();
|
||||
void on_statistics_update(const ChannelStatistics& statistics);
|
||||
void set_display_freq(int64_t freq);
|
||||
void on_timer();
|
||||
|
||||
uint8_t freq_index = 0;
|
||||
rf::Frequency freq_ = {433920000};
|
||||
int32_t beep_squelch = 0;
|
||||
audio::Rate audio_sampling_rate = audio::Rate::Hz_48000;
|
||||
uint8_t freq_mode = 0;
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_detector",
|
||||
app_settings::Mode::RX,
|
||||
{
|
||||
{"beep_squelch"sv, &beep_squelch},
|
||||
}};
|
||||
|
||||
Labels labels{
|
||||
{{UI_POS_X(0), UI_POS_Y(0)}, "LNA: VGA: AMP: VOL: ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
LNAGainField field_lna{
|
||||
{UI_POS_X(4), UI_POS_Y(0)}};
|
||||
|
||||
VGAGainField field_vga{
|
||||
{UI_POS_X(11), UI_POS_Y(0)}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{UI_POS_X(24), UI_POS_Y(0)}};
|
||||
|
||||
OptionsField field_mode{
|
||||
{UI_POS_X(0), UI_POS_Y(1)},
|
||||
9,
|
||||
{
|
||||
{"TETRA UP", 0},
|
||||
{"Lora", 1},
|
||||
{"Remotes", 2},
|
||||
}};
|
||||
|
||||
Text text_frequency{
|
||||
{UI_POS_X_RIGHT(20), UI_POS_Y(1), UI_POS_WIDTH(20), UI_POS_DEFAULT_HEIGHT},
|
||||
""};
|
||||
|
||||
Text text_beep_squelch{
|
||||
{UI_POS_X_RIGHT(9), UI_POS_Y(2), UI_POS_WIDTH(4), UI_POS_DEFAULT_HEIGHT},
|
||||
"Bip>"};
|
||||
|
||||
NumberField field_beep_squelch{
|
||||
{UI_POS_X_RIGHT(5), UI_POS_Y(2)},
|
||||
4,
|
||||
{-100, 20},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
// RSSI: XX/XX/XXX
|
||||
Text freq_stats_rssi{
|
||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
||||
};
|
||||
|
||||
// Power: -XXX db
|
||||
Text freq_stats_db{
|
||||
{UI_POS_X(0), UI_POS_Y(3), UI_POS_WIDTH(15), UI_POS_DEFAULT_HEIGHT},
|
||||
};
|
||||
|
||||
RSSIGraph rssi_graph{
|
||||
{UI_POS_X(0), UI_POS_Y(5), UI_POS_WIDTH_REMAINING(5), UI_POS_HEIGHT_REMAINING(6)},
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
{UI_POS_X_RIGHT(5), UI_POS_Y(5), UI_POS_WIDTH(5), UI_POS_HEIGHT_REMAINING(6)},
|
||||
};
|
||||
|
||||
MessageHandlerRegistration message_handler_stats{
|
||||
Message::ID::ChannelStatistics,
|
||||
[this](const Message* const p) {
|
||||
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
|
||||
}};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
Message::ID::DisplayFrameSync,
|
||||
[this](const Message* const) {
|
||||
this->on_timer();
|
||||
}};
|
||||
|
||||
const std::vector<uint32_t> remotes_monitoring_frequencies_hz = {
|
||||
// Around 315 MHz (common for older remotes, key fobs in some regions)
|
||||
// Window centered on 315 MHz, covers 314.625 - 315.375 MHz
|
||||
315000000,
|
||||
|
||||
// Around 433.92 MHz (very common for remotes, sensors, key fobs globally)
|
||||
// Window centered on 433.92 MHz, covers 433.545 - 434.295 MHz
|
||||
433920000,
|
||||
};
|
||||
const std::vector<uint32_t> lora_monitoring_frequencies_hz = {
|
||||
// EU433 Band (Europe, typically 433.05 MHz to 434.79 MHz)
|
||||
// Scanning the approximate range 433.0 MHz to 434.8 MHz with 750kHz steps
|
||||
433375000, // Covers 433.000 - 433.750 MHz
|
||||
434125000, // Covers 433.750 - 434.500 MHz (includes 433.92 MHz)
|
||||
434875000, // Covers 434.500 - 435.250 MHz (covers up to 434.79 MHz)
|
||||
|
||||
// EU868 Band (Europe, typically 863 MHz to 870 MHz, specific channels around 868 MHz)
|
||||
// Targeting common LoRaWAN channel groups (approx 867.0 - 868.6 MHz) with 750kHz steps
|
||||
867375000, // Covers 867.000 - 867.750 MHz
|
||||
868125000, // Covers 867.750 - 868.500 MHz
|
||||
868875000, // Covers 868.500 - 869.250 MHz (covers up to 868.6 MHz)
|
||||
|
||||
// US915 Band (North America, typically 902 MHz to 928 MHz, specific channels around 915 MHz)
|
||||
// Providing a few sample windows around the 915 MHz area with 750kHz steps.
|
||||
// This band is wide; a full scan would require many more frequencies.
|
||||
914250000, // Covers 913.875 - 914.625 MHz
|
||||
915000000, // Covers 914.625 - 915.375 MHz (Centered on 915 MHz)
|
||||
915750000, // Covers 915.375 - 916.125 MHz
|
||||
};
|
||||
const std::vector<uint32_t> tetra_uplink_monitoring_frequencies_hz = {
|
||||
// Band starts at 380,000,000 Hz, ends at 390,000,000 Hz.
|
||||
// First center: 380,000,000 + 375,000 = 380,375,000 Hz
|
||||
// Last center: 380,375,000 + 13 * 750,000 = 390,125,000 Hz (14 frequencies total for this band)
|
||||
380375000, // Covers 380.000 - 380.750 MHz
|
||||
381125000, // Covers 380.750 - 381.500 MHz
|
||||
381875000, // Covers 381.500 - 382.250 MHz
|
||||
382625000, // Covers 382.250 - 383.000 MHz
|
||||
383375000, // Covers 383.000 - 383.750 MHz
|
||||
384125000, // Covers 383.750 - 384.500 MHz
|
||||
384875000, // Covers 384.500 - 385.250 MHz
|
||||
385625000, // Covers 385.250 - 386.000 MHz
|
||||
386375000, // Covers 386.000 - 386.750 MHz
|
||||
387125000, // Covers 386.750 - 387.500 MHz
|
||||
387875000, // Covers 387.500 - 388.250 MHz
|
||||
388625000, // Covers 388.250 - 389.000 MHz
|
||||
389375000, // Covers 389.000 - 389.750 MHz
|
||||
390125000, // Covers 389.750 - 390.500 MHz
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace ui::external_app::detector_rx
|
||||
|
||||
#endif
|
||||
+10
-5
@@ -12,11 +12,11 @@
|
||||
namespace ui::external_app::doom {
|
||||
|
||||
//clang-format off
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 320
|
||||
#define RENDER_HEIGHT 280
|
||||
#define HALF_WIDTH (SCREEN_WIDTH / 2)
|
||||
#define HALF_HEIGHT (RENDER_HEIGHT / 2)
|
||||
int SCREEN_WIDTH = 0;
|
||||
int SCREEN_HEIGHT = 0;
|
||||
int RENDER_HEIGHT = 0;
|
||||
int HALF_WIDTH = 0;
|
||||
int HALF_HEIGHT = 0;
|
||||
#define LEVEL_WIDTH_BASE 6
|
||||
#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE)
|
||||
#define LEVEL_HEIGHT 57
|
||||
@@ -1001,6 +1001,11 @@ void render_map(Painter& painter, bool full_clear, int16_t x_start = 0, int16_t
|
||||
|
||||
DoomView::DoomView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
SCREEN_WIDTH = screen_width;
|
||||
SCREEN_HEIGHT = screen_height;
|
||||
RENDER_HEIGHT = screen_height - 40;
|
||||
HALF_WIDTH = screen_width / 2;
|
||||
HALF_HEIGHT = RENDER_HEIGHT / 2;
|
||||
add_children({&dummy});
|
||||
game_timer.attach(&game_timer_check, 1.0 / 60.0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ class DoomView : public View {
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
Button dummy{{240, 0, 0, 0}, ""};
|
||||
Button dummy{{screen_width, 0, 0, 0}, ""};
|
||||
bool initialized{false};
|
||||
bool prev_velocity_moving{false};
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
@@ -212,6 +212,10 @@ set(EXTCPPSRC
|
||||
#gfxEQ
|
||||
external/gfxeq/main.cpp
|
||||
external/gfxeq/ui_gfxeq.cpp
|
||||
|
||||
#detector_rx
|
||||
external/detector_rx/main.cpp
|
||||
external/detector_rx/ui_detector_rx.cpp
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -266,4 +270,5 @@ set(EXTAPPLIST
|
||||
scanner
|
||||
level
|
||||
gfxeq
|
||||
detector_rx
|
||||
)
|
||||
|
||||
+10
@@ -74,6 +74,7 @@ MEMORY
|
||||
ram_external_app_level (rwx) : org = 0xADE10000, len = 32k
|
||||
ram_external_app_gfxeq (rwx) : org = 0xADE20000, len = 32k
|
||||
ram_external_app_noaaapt_rx (rwx) : org = 0xADE30000, len = 32k
|
||||
ram_external_app_detector_rx (rwx) : org = 0xADE40000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -383,4 +384,13 @@ SECTIONS
|
||||
KEEP(*(.external_app.app_gfxeq.application_information));
|
||||
*(*ui*external_app*gfxeq*);
|
||||
} > ram_external_app_gfxeq
|
||||
|
||||
.external_app_detector_rx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_detector_rx.application_information));
|
||||
*(*ui*external_app*detector_rx*);
|
||||
} > ram_external_app_detector_rx
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class ExtSensorsView : public View {
|
||||
{{0 * 8, 5 * 16}, "ORI:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 7 * 16}, "ENV:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Text text_info{{0 * 8, 0 * 8, 30 * 8, 16 * 1}, "Connect a compatible module..."};
|
||||
Text text_info{{0 * 8, 0 * 8, screen_width, 16 * 1}, "Connect a compatible module..."};
|
||||
Text text_gps{{5 * 8, 3 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
|
||||
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
|
||||
|
||||
+2
-2
@@ -89,7 +89,7 @@ class FmRadioView : public View {
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
@@ -103,7 +103,7 @@ class FmRadioView : public View {
|
||||
{21 * 8, 10, 6 * 8, 4}};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 20, 30 * 8, 2 * 16},
|
||||
{0, 20, screen_width, 2 * 16},
|
||||
audio_spectrum,
|
||||
128,
|
||||
0,
|
||||
|
||||
+3
-3
@@ -62,7 +62,7 @@ class FoxhuntRxView : public View {
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
@@ -73,7 +73,7 @@ class FoxhuntRxView : public View {
|
||||
{0 * 8, 2 * 16 + 4, 14 * 8, 14},
|
||||
};
|
||||
RSSIGraph rssi_graph{
|
||||
{0, 50, 240, 30},
|
||||
{0, 50, screen_width, 30},
|
||||
};
|
||||
|
||||
Button clear_markers{
|
||||
@@ -84,7 +84,7 @@ class FoxhuntRxView : public View {
|
||||
{2, 18, 7 * 8, 16},
|
||||
"Mark"};
|
||||
|
||||
GeoMap geomap{{0, 80, 240, 240}};
|
||||
GeoMap geomap{{0, 80, screen_width, screen_height - 80}};
|
||||
|
||||
MessageHandlerRegistration message_handler_gps{
|
||||
Message::ID::GPSPosData,
|
||||
|
||||
+4
-4
@@ -32,7 +32,7 @@ gfxEQView::gfxEQView(NavigationView& nav)
|
||||
baseband::run_image(portapack::spi_flash::image_tag_wfm_audio);
|
||||
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio);
|
||||
receiver_model.set_wfm_configuration(1); // 200k => 0 , 180k => 1 , 40k => 2. Set to 1 or 2 for better reception
|
||||
receiver_model.set_wfm_configuration(1); // 200k => 0 , 180k => 1 , 80k => 2. Set to 1 or 2 for better reception
|
||||
receiver_model.set_sampling_rate(3072000);
|
||||
receiver_model.set_baseband_bandwidth(1750000);
|
||||
|
||||
@@ -165,12 +165,12 @@ void gfxEQView::render_equalizer(Painter& painter) {
|
||||
|
||||
if (prev_bar_heights[bar] > active_segments) {
|
||||
int clear_height = (prev_bar_heights[bar] - active_segments) * SEGMENT_HEIGHT;
|
||||
int clear_y = SCREEN_HEIGHT - prev_bar_heights[bar] * SEGMENT_HEIGHT;
|
||||
int clear_y = screen_height - prev_bar_heights[bar] * SEGMENT_HEIGHT;
|
||||
painter.fill_rectangle({x, clear_y, BAR_WIDTH, clear_height}, Color(0, 0, 0));
|
||||
}
|
||||
|
||||
for (int seg = 0; seg < active_segments; seg++) {
|
||||
int y = SCREEN_HEIGHT - (seg + 1) * SEGMENT_HEIGHT;
|
||||
int y = screen_height - (seg + 1) * SEGMENT_HEIGHT;
|
||||
if (y < header_height) break;
|
||||
|
||||
Color segment_color = (seg >= active_segments - 2 && seg < active_segments) ? theme.peak_color : theme.base_color;
|
||||
@@ -183,7 +183,7 @@ void gfxEQView::render_equalizer(Painter& painter) {
|
||||
|
||||
void gfxEQView::paint(Painter& painter) {
|
||||
if (needs_background_redraw) {
|
||||
painter.fill_rectangle({0, header_height, SCREEN_WIDTH, RENDER_HEIGHT}, Color(0, 0, 0));
|
||||
painter.fill_rectangle({0, header_height, screen_width, RENDER_HEIGHT}, Color(0, 0, 0));
|
||||
needs_background_redraw = false;
|
||||
}
|
||||
render_equalizer(painter);
|
||||
|
||||
+2
-4
@@ -40,12 +40,10 @@ class gfxEQView : public View {
|
||||
|
||||
private:
|
||||
static constexpr ui::Dim header_height = 2 * 16;
|
||||
static constexpr int SCREEN_WIDTH = 240;
|
||||
static constexpr int SCREEN_HEIGHT = 320;
|
||||
static constexpr int RENDER_HEIGHT = 288;
|
||||
static constexpr int NUM_BARS = 11;
|
||||
static constexpr int BAR_SPACING = 2;
|
||||
static constexpr int BAR_WIDTH = (SCREEN_WIDTH - (BAR_SPACING * (NUM_BARS - 1))) / NUM_BARS;
|
||||
int BAR_WIDTH = (screen_width - (BAR_SPACING * (NUM_BARS - 1))) / NUM_BARS;
|
||||
static constexpr int HORIZONTAL_OFFSET = 2;
|
||||
static constexpr int SEGMENT_HEIGHT = 10;
|
||||
|
||||
@@ -101,7 +99,7 @@ class gfxEQView : public View {
|
||||
LNAGainField field_lna{{15 * 8, 0 * 16}};
|
||||
VGAGainField field_vga{{18 * 8, 0 * 16}};
|
||||
Button button_mood{{21 * 8, 0, 6 * 8, 16}, "MOOD"};
|
||||
AudioVolumeField field_volume{{28 * 8, 0 * 16}};
|
||||
AudioVolumeField field_volume{{screen_width - 2 * 8, 0 * 16}};
|
||||
|
||||
rf::Frequency frequency_value{93100000};
|
||||
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ class GpsSimAppView : public View {
|
||||
LanguageHelper::currentMessages[LANG_LOOP],
|
||||
true};
|
||||
ImageButton button_play{
|
||||
{28 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, 2 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
+130
-49
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2025 RocketGod - Added modes from my Flipper Zero RF Jammer App - https://betaskynet.com
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -36,7 +37,6 @@ void RangeView::focus() {
|
||||
}
|
||||
|
||||
void RangeView::update_start(rf::Frequency f) {
|
||||
// Change everything except max
|
||||
frequency_range.min = f;
|
||||
button_start.set_text(to_string_short_freq(f));
|
||||
|
||||
@@ -48,7 +48,6 @@ void RangeView::update_start(rf::Frequency f) {
|
||||
}
|
||||
|
||||
void RangeView::update_stop(rf::Frequency f) {
|
||||
// Change everything except min
|
||||
frequency_range.max = f;
|
||||
button_stop.set_text(to_string_short_freq(f));
|
||||
|
||||
@@ -60,7 +59,6 @@ void RangeView::update_stop(rf::Frequency f) {
|
||||
}
|
||||
|
||||
void RangeView::update_center(rf::Frequency f) {
|
||||
// Change min/max/center, keep width
|
||||
center = f;
|
||||
button_center.set_text(to_string_short_freq(center));
|
||||
|
||||
@@ -75,7 +73,6 @@ void RangeView::update_center(rf::Frequency f) {
|
||||
}
|
||||
|
||||
void RangeView::update_width(uint32_t w) {
|
||||
// Change min/max/width, keep center
|
||||
width = w;
|
||||
|
||||
button_width.set_text(to_string_short_freq(width));
|
||||
@@ -91,7 +88,6 @@ void RangeView::update_width(uint32_t w) {
|
||||
}
|
||||
|
||||
void RangeView::paint(Painter&) {
|
||||
// Draw lines and arrows
|
||||
Rect r;
|
||||
Point p;
|
||||
Coord c;
|
||||
@@ -162,7 +158,7 @@ RangeView::RangeView(NavigationView& nav) {
|
||||
auto load_view = nav.push<FrequencyLoadView>();
|
||||
load_view->on_frequency_loaded = [this](rf::Frequency value) {
|
||||
update_center(value);
|
||||
update_width(100000); // 100kHz default jamming bandwidth when loading unique frequency
|
||||
update_width(100000);
|
||||
};
|
||||
load_view->on_range_loaded = [this](rf::Frequency start, rf::Frequency stop) {
|
||||
update_start(start);
|
||||
@@ -193,10 +189,37 @@ void JammerView::set_jammer_channel(uint32_t i, uint32_t width, uint64_t center,
|
||||
jammer_channels[i].enabled = true;
|
||||
jammer_channels[i].width = (width * 0xFFFFFFULL) / 1536000;
|
||||
jammer_channels[i].center = center;
|
||||
jammer_channels[i].duration = 30720 * duration;
|
||||
jammer_channels[i].duration = duration ? 30720 * duration : 3000;
|
||||
}
|
||||
|
||||
void JammerView::start_tx() {
|
||||
if (update_config()) {
|
||||
jamming = true;
|
||||
button_transmit.set_style(&style_cancel);
|
||||
button_transmit.set_text("STOP");
|
||||
|
||||
transmitter_model.set_rf_amp(field_amp.value());
|
||||
transmitter_model.set_tx_gain(field_gain.value());
|
||||
transmitter_model.set_baseband_bandwidth(28'000'000);
|
||||
transmitter_model.enable();
|
||||
|
||||
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
mscounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void JammerView::stop_tx() {
|
||||
button_transmit.set_style(&style_val);
|
||||
button_transmit.set_text("START");
|
||||
transmitter_model.disable();
|
||||
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
|
||||
jamming = false;
|
||||
cooling = false;
|
||||
seconds = 0;
|
||||
mscounter = 0;
|
||||
}
|
||||
|
||||
bool JammerView::update_config() {
|
||||
uint32_t c, i = 0;
|
||||
size_t num_channels;
|
||||
rf::Frequency start_freq, range_bw, range_bw_sub, ch_width;
|
||||
@@ -204,24 +227,19 @@ void JammerView::start_tx() {
|
||||
|
||||
size_t hop_value = options_hop.selected_index_value();
|
||||
|
||||
// Disable all channels by default
|
||||
for (c = 0; c < JAMMER_MAX_CH; c++)
|
||||
jammer_channels[c].enabled = false;
|
||||
|
||||
// Generate jamming channels with JAMMER_MAX_CH maximum width
|
||||
// Convert ranges min/max to center/bw
|
||||
for (size_t r = 0; r < 3; r++) {
|
||||
if (range_views[r]->frequency_range.enabled) {
|
||||
range_bw = abs(range_views[r]->frequency_range.max - range_views[r]->frequency_range.min);
|
||||
|
||||
// Get lower bound
|
||||
if (range_views[r]->frequency_range.min < range_views[r]->frequency_range.max)
|
||||
start_freq = range_views[r]->frequency_range.min;
|
||||
else
|
||||
start_freq = range_views[r]->frequency_range.max;
|
||||
|
||||
if (range_bw >= JAMMER_CH_WIDTH) {
|
||||
// Split range in multiple channels
|
||||
num_channels = 0;
|
||||
range_bw_sub = range_bw;
|
||||
|
||||
@@ -241,7 +259,6 @@ void JammerView::start_tx() {
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
// Range fits in a single channel
|
||||
if (i >= JAMMER_MAX_CH) {
|
||||
out_of_ranges = true;
|
||||
} else {
|
||||
@@ -254,43 +271,24 @@ void JammerView::start_tx() {
|
||||
|
||||
if (!out_of_ranges && i) {
|
||||
text_range_total.set("/" + to_string_dec_uint(i, 2));
|
||||
|
||||
jamming = true;
|
||||
button_transmit.set_style(&style_cancel);
|
||||
button_transmit.set_text("STOP");
|
||||
|
||||
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());
|
||||
mscounter = 0; // euquiq: Reset internal ms counter for do_timer()
|
||||
return true;
|
||||
} else {
|
||||
if (out_of_ranges)
|
||||
nav_.display_modal("Error", "Jamming bandwidth too large.\nMust be less than 24MHz.");
|
||||
else
|
||||
nav_.display_modal("Error", "No range enabled.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void JammerView::stop_tx() {
|
||||
button_transmit.set_style(&style_val);
|
||||
button_transmit.set_text("START");
|
||||
transmitter_model.disable();
|
||||
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
|
||||
jamming = false;
|
||||
cooling = false;
|
||||
}
|
||||
|
||||
// called each 1/60th of second
|
||||
void JammerView::on_timer() {
|
||||
if (++mscounter == 60) {
|
||||
if (++mscounter >= 60) {
|
||||
mscounter = 0;
|
||||
if (jamming) {
|
||||
int32_t timepause = field_timepause.value();
|
||||
if (cooling) {
|
||||
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 .
|
||||
if (timepause == 0 || ++seconds >= timepause) {
|
||||
transmitter_model.set_baseband_bandwidth(28'000'000);
|
||||
transmitter_model.enable();
|
||||
button_transmit.set_text("STOP");
|
||||
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
@@ -306,8 +304,7 @@ void JammerView::on_timer() {
|
||||
seconds = 0;
|
||||
}
|
||||
} else {
|
||||
if (++seconds >= field_timetx.value()) // Start cooling period:
|
||||
{
|
||||
if (timepause && ++seconds >= field_timetx.value()) {
|
||||
transmitter_model.disable();
|
||||
button_transmit.set_text("PAUSED");
|
||||
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
|
||||
@@ -327,11 +324,9 @@ void JammerView::on_timer() {
|
||||
}
|
||||
}
|
||||
|
||||
JammerView::JammerView(
|
||||
NavigationView& nav)
|
||||
JammerView::JammerView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
Rect view_rect = {0, 3 * 8, 240, 80};
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_jammer);
|
||||
Rect view_rect = {0, 3 * 8, screen_width, 80};
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&tab_view,
|
||||
@@ -355,15 +350,101 @@ JammerView::JammerView(
|
||||
view_range_b.set_parent_rect(view_rect);
|
||||
view_range_c.set_parent_rect(view_rect);
|
||||
|
||||
options_type.set_selected_index(3); // Rand CW
|
||||
options_speed.set_selected_index(3); // 10kHz
|
||||
options_hop.set_selected_index(1); // 50ms
|
||||
button_transmit.set_style(&style_val);
|
||||
view_range_a.check_enabled.set_value(true);
|
||||
view_range_a.frequency_range.enabled = true;
|
||||
view_range_a.update_center(315'000'000);
|
||||
view_range_a.update_width(1'000'000);
|
||||
|
||||
options_type.set_selected_index(3);
|
||||
options_speed.set_selected_index(3);
|
||||
options_hop.set_selected_index(0);
|
||||
field_timetx.set_value(30);
|
||||
field_timepause.set_value(1);
|
||||
field_timepause.set_value(0);
|
||||
field_jitter.set_value(0);
|
||||
field_gain.set_value(transmitter_model.tx_gain());
|
||||
field_amp.set_value(transmitter_model.rf_amp());
|
||||
button_transmit.set_style(&style_val);
|
||||
|
||||
options_type.on_change = [this](size_t, OptionsField::value_t) {
|
||||
if (jamming) update_config();
|
||||
if (jamming && !cooling) baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
};
|
||||
|
||||
options_speed.on_change = [this](size_t, OptionsField::value_t) {
|
||||
if (jamming) update_config();
|
||||
if (jamming && !cooling) baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
|
||||
};
|
||||
|
||||
options_hop.on_change = [this](size_t, OptionsField::value_t) {
|
||||
if (jamming) update_config();
|
||||
};
|
||||
|
||||
field_timetx.on_change = [this](int32_t) {
|
||||
if (jamming) update_config();
|
||||
};
|
||||
|
||||
field_timepause.on_change = [this](int32_t) {
|
||||
if (jamming) update_config();
|
||||
};
|
||||
|
||||
field_jitter.on_change = [this](int32_t) {
|
||||
if (jamming) update_config();
|
||||
};
|
||||
|
||||
field_gain.on_change = [this](int32_t v) {
|
||||
if (jamming) transmitter_model.set_tx_gain(v);
|
||||
};
|
||||
|
||||
field_amp.on_change = [this](int32_t v) {
|
||||
if (jamming) transmitter_model.set_rf_amp(v);
|
||||
};
|
||||
|
||||
for (auto range_view : range_views) {
|
||||
range_view->check_enabled.on_select = [this](Checkbox&, bool) {
|
||||
if (jamming) update_config();
|
||||
};
|
||||
range_view->button_start.on_select = [this, range_view](Button&) {
|
||||
auto new_view = nav_.push<FrequencyKeypadView>(range_view->frequency_range.min);
|
||||
new_view->on_changed = [this, range_view](rf::Frequency f) {
|
||||
range_view->update_start(f);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
};
|
||||
range_view->button_stop.on_select = [this, range_view](Button&) {
|
||||
auto new_view = nav_.push<FrequencyKeypadView>(range_view->frequency_range.max);
|
||||
new_view->on_changed = [this, range_view](rf::Frequency f) {
|
||||
range_view->update_stop(f);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
};
|
||||
range_view->button_center.on_select = [this, range_view](Button&) {
|
||||
auto new_view = nav_.push<FrequencyKeypadView>(range_view->center);
|
||||
new_view->on_changed = [this, range_view](rf::Frequency f) {
|
||||
range_view->update_center(f);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
};
|
||||
range_view->button_width.on_select = [this, range_view](Button&) {
|
||||
auto new_view = nav_.push<FrequencyKeypadView>(range_view->width);
|
||||
new_view->on_changed = [this, range_view](rf::Frequency f) {
|
||||
range_view->update_width(f);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
};
|
||||
range_view->button_load_range.on_select = [this, range_view](Button&) {
|
||||
auto load_view = nav_.push<FrequencyLoadView>();
|
||||
load_view->on_frequency_loaded = [this, range_view](rf::Frequency value) {
|
||||
range_view->update_center(value);
|
||||
range_view->update_width(100000);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
load_view->on_range_loaded = [this, range_view](rf::Frequency start, rf::Frequency stop) {
|
||||
range_view->update_start(start);
|
||||
range_view->update_stop(stop);
|
||||
if (jamming) update_config();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
button_transmit.on_select = [this](Button&) {
|
||||
if (jamming || cooling)
|
||||
|
||||
+29
-25
@@ -41,27 +41,12 @@ class RangeView : public View {
|
||||
RangeView(NavigationView& nav);
|
||||
|
||||
void focus() override;
|
||||
void paint(Painter&) override;
|
||||
void paint(Painter& painter) override;
|
||||
|
||||
jammer_range_t frequency_range{false, 0, 0};
|
||||
|
||||
private:
|
||||
void update_start(rf::Frequency f);
|
||||
void update_stop(rf::Frequency f);
|
||||
void update_center(rf::Frequency f);
|
||||
void update_width(uint32_t w);
|
||||
|
||||
uint32_t width{};
|
||||
rf::Frequency center{};
|
||||
|
||||
const Style& style_info = *Theme::getInstance()->fg_medium;
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Theme::getInstance()->fg_light->foreground},
|
||||
{{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Theme::getInstance()->fg_light->foreground},
|
||||
{{12 * 8, 5 * 8 - 4}, "Center", Theme::getInstance()->fg_light->foreground},
|
||||
{{12 * 8 + 4, 13 * 8}, "Width", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
Checkbox check_enabled{
|
||||
{1 * 8, 4},
|
||||
12,
|
||||
@@ -74,15 +59,32 @@ class RangeView : public View {
|
||||
Button button_start{
|
||||
{0 * 8, 11 * 8, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
Button button_stop{
|
||||
{19 * 8, 11 * 8, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
Button button_center{
|
||||
{76, 4 * 15 - 4, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
Button button_width{
|
||||
{76, 8 * 15, 11 * 8, 28},
|
||||
""};
|
||||
|
||||
void update_start(rf::Frequency f);
|
||||
void update_stop(rf::Frequency f);
|
||||
void update_center(rf::Frequency f);
|
||||
void update_width(uint32_t w);
|
||||
|
||||
private:
|
||||
const Style& style_info = *Theme::getInstance()->fg_medium;
|
||||
|
||||
Labels labels{
|
||||
{{2 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_START], Theme::getInstance()->fg_light->foreground},
|
||||
{{23 * 8, 8 * 8 + 4}, LanguageHelper::currentMessages[LANG_STOP], Theme::getInstance()->fg_light->foreground},
|
||||
{{12 * 8, 5 * 8 - 4}, "Center", Theme::getInstance()->fg_light->foreground},
|
||||
{{12 * 8 + 4, 13 * 8}, "Width", Theme::getInstance()->fg_light->foreground}};
|
||||
};
|
||||
|
||||
class JammerView : public View {
|
||||
@@ -110,15 +112,16 @@ class JammerView : public View {
|
||||
void start_tx();
|
||||
void on_timer();
|
||||
void stop_tx();
|
||||
bool update_config();
|
||||
void set_jammer_channel(uint32_t i, uint32_t width, uint64_t center, uint32_t duration);
|
||||
void on_retune(const rf::Frequency freq, const uint32_t range);
|
||||
|
||||
JammerChannel* jammer_channels = (JammerChannel*)shared_memory.bb_data.data;
|
||||
bool jamming{false};
|
||||
bool cooling{false}; // euquiq: Indicates jammer in cooldown
|
||||
uint16_t seconds = 0; // euquiq: seconds counter for toggling tx / cooldown
|
||||
int16_t mscounter = 0; // euquiq: Internal ms counter for do_timer()
|
||||
lfsr_word_t lfsr_v = 1; // euquiq: Used to generate "random" Jitter
|
||||
bool cooling{false};
|
||||
uint16_t seconds{0};
|
||||
int16_t mscounter{0};
|
||||
lfsr_word_t lfsr_v{1};
|
||||
|
||||
const Style& style_val = *Theme::getInstance()->fg_green;
|
||||
const Style& style_cancel = *Theme::getInstance()->fg_red;
|
||||
@@ -140,8 +143,8 @@ class JammerView : public View {
|
||||
{{1 * 8, 25 * 8}, "Speed:", Theme::getInstance()->fg_light->foreground},
|
||||
{{3 * 8, 27 * 8}, "Hop:", Theme::getInstance()->fg_light->foreground},
|
||||
{{4 * 8, 29 * 8}, "TX:", Theme::getInstance()->fg_light->foreground},
|
||||
{{1 * 8, 31 * 8}, "Sle3p:", Theme::getInstance()->fg_light->foreground}, // euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty.
|
||||
{{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground}, // Maybe the repository curator can keep the "mystype" for some versions.
|
||||
{{1 * 8, 31 * 8}, "Sleep:", Theme::getInstance()->fg_light->foreground},
|
||||
{{0 * 8, 33 * 8}, "Jitter:", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 29 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 31 * 8}, "Secs.", Theme::getInstance()->fg_light->foreground},
|
||||
{{11 * 8, 33 * 8}, "/60", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -182,7 +185,8 @@ class JammerView : public View {
|
||||
OptionsField options_hop{
|
||||
{7 * 8, 27 * 8},
|
||||
5,
|
||||
{{"10ms ", 1},
|
||||
{{"Off ", 0},
|
||||
{"10ms ", 1},
|
||||
{"50ms ", 5},
|
||||
{"100ms", 10},
|
||||
{"1s ", 100},
|
||||
@@ -201,7 +205,7 @@ class JammerView : public View {
|
||||
NumberField field_timepause{
|
||||
{8 * 8, 31 * 8},
|
||||
2,
|
||||
{1, 60},
|
||||
{0, 60},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
@@ -209,7 +213,7 @@ class JammerView : public View {
|
||||
NumberField field_jitter{
|
||||
{8 * 8, 33 * 8},
|
||||
2,
|
||||
{1, 60},
|
||||
{0, 60},
|
||||
1,
|
||||
' ',
|
||||
};
|
||||
|
||||
+2
-2
@@ -178,12 +178,12 @@ class LevelView : public View {
|
||||
|
||||
RSSIGraph rssi_graph{
|
||||
// 240x320 =>
|
||||
{0, 6 * 16 + 8, 240 - 5 * 8, 320 - (6 * 16)},
|
||||
{0, 6 * 16 + 8, screen_width - 5 * 8, screen_height - (6 * 16)},
|
||||
};
|
||||
|
||||
RSSI rssi{
|
||||
// 240x320 =>
|
||||
{240 - 5 * 8, 6 * 16 + 8, 5 * 8, 320 - (6 * 16)},
|
||||
{screen_width - 5 * 8, 6 * 16 + 8, 5 * 8, screen_height - (6 * 16)},
|
||||
};
|
||||
|
||||
void handle_coded_squelch(const uint32_t value);
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ class LGEView : public View {
|
||||
'0'};
|
||||
|
||||
Console console{
|
||||
{0, 18 * 8, 30 * 8, 7 * 16}};
|
||||
{0, 18 * 8, screen_width, 7 * 16}};
|
||||
|
||||
TransmitterView tx_view{
|
||||
16 * 16,
|
||||
|
||||
@@ -72,16 +72,16 @@ class McuTemperatureView : public View {
|
||||
|
||||
private:
|
||||
Text text_title{
|
||||
{76, 16, 240, 16},
|
||||
{76, 16, screen_width, 16},
|
||||
"Temperature",
|
||||
};
|
||||
|
||||
McuTemperatureWidget temperature_widget{
|
||||
{0, 40, 240, 180},
|
||||
{0, 40, screen_width, 180},
|
||||
};
|
||||
|
||||
Button button_done{
|
||||
{72, 264, 96, 24},
|
||||
{72, screen_height - 56, 96, 24},
|
||||
"Done"};
|
||||
};
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ void NoaaAptRxView::on_status(NoaaAptRxStatusDataMessage msg) {
|
||||
|
||||
// this stores and displays the image. keep it as simple as you can. a bit more complexity will kill the sync
|
||||
void NoaaAptRxView::on_image(NoaaAptRxImageDataMessage msg) {
|
||||
if ((line_num) >= 320 - NOAA_IMG_START_ROW * 16) line_num = 0; // for draw reset
|
||||
if ((line_num) >= UI_POS_HEIGHT_REMAINING(NOAA_IMG_START_ROW)) line_num = 0; // for draw reset
|
||||
|
||||
for (uint16_t i = 0; i < msg.cnt; i += 1) {
|
||||
Color pxl = {msg.image[i], msg.image[i], msg.image[i]};
|
||||
|
||||
+10
-15
@@ -81,22 +81,22 @@ class NoaaAptRxView : public View {
|
||||
{}};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{UI_POS_X(13), UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{UI_POS_X(15), UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH(6), 4}};
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(2), UI_POS_MAXWIDTH, UI_POS_DEFAULT_HEIGHT},
|
||||
u"AUD",
|
||||
u"AUDIO",
|
||||
RecordView::FileType::WAV,
|
||||
@@ -104,22 +104,17 @@ class NoaaAptRxView : public View {
|
||||
4};
|
||||
|
||||
Checkbox check_wav{
|
||||
{0 * 8, 2 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(2)},
|
||||
12,
|
||||
"Save WAV too",
|
||||
true};
|
||||
|
||||
/*Labels labels{
|
||||
{{1 * 8, 1 * 16}, "LPM:", Theme::getInstance()->fg_light->foreground},
|
||||
{{13 * 8, 1 * 16}, "IOC:", Theme::getInstance()->fg_light->foreground},
|
||||
};*/
|
||||
|
||||
Text txt_status{
|
||||
{0 * 8, 1 * 16, 20 * 8, 16},
|
||||
{UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(20), UI_POS_DEFAULT_HEIGHT},
|
||||
};
|
||||
|
||||
Button button_ss{
|
||||
{190, 1 * 16, 5 * 8, 16},
|
||||
{UI_POS_X_RIGHT(6), UI_POS_Y(1), UI_POS_WIDTH(5), UI_POS_DEFAULT_HEIGHT},
|
||||
LanguageHelper::currentMessages[LANG_START]};
|
||||
|
||||
MessageHandlerRegistration message_handler_stats{
|
||||
|
||||
+2
-2
@@ -77,11 +77,11 @@ class NRFRxView : public View {
|
||||
nav_};
|
||||
|
||||
Button button_modem_setup{
|
||||
{240 - 12 * 8, 1 * 16, 96, 24},
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, 240}};
|
||||
{0, 4 * 16, screen_width, screen_height - 80}};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::AFSKData,
|
||||
|
||||
@@ -109,7 +109,7 @@ class OOKEditorAppView : public View {
|
||||
Labels label_waveform{{{0, 188}, "Waveform:", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
// Text field to display the various status message of the app
|
||||
Text text_app_status{{0, 160, 30 * 8, 16}, ""};
|
||||
Text text_app_status{{0, 160, screen_width, 16}, ""};
|
||||
|
||||
// OptionsField for selectable sample rates.
|
||||
OptionsField field_sample_rate{{96, 20}, 7, {{"250k", 250000U}, {"1M", 1000000U}, {"2M", 2000000U}, {"5M", 5000000U}, {"10M", 10000000U}, {"20M", 20000000U}}};
|
||||
@@ -121,7 +121,7 @@ class OOKEditorAppView : public View {
|
||||
NumberField field_repeat{{210, 40}, 3, {1, 999}, 1, '0', false};
|
||||
|
||||
// Text field to display the payload data.
|
||||
Text text_payload{{0 * 8, 100, 30 * 8, 16}, ""};
|
||||
Text text_payload{{0 * 8, 100, screen_width, 16}, ""};
|
||||
|
||||
// Buttons for setting configurations, opening files, and starting transmission.
|
||||
Button button_set{{0, 125, 60, 28}, LanguageHelper::currentMessages[LANG_SET]};
|
||||
@@ -134,7 +134,7 @@ class OOKEditorAppView : public View {
|
||||
ProgressBar progressbar{{2 * 8, 250, 208, 16}};
|
||||
|
||||
// Waveform display using waveform buffer and yellow theme color.
|
||||
Waveform waveform{{0, 208, 240, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
|
||||
Waveform waveform{{0, 208, screen_width, 32}, waveform_buffer, 0, 0, true, Theme::getInstance()->fg_yellow->foreground};
|
||||
};
|
||||
|
||||
/******** bug key input view **********/
|
||||
|
||||
@@ -56,7 +56,7 @@ class PlaylistEditorView : public View {
|
||||
"New"};
|
||||
|
||||
Text text_current_ppl_file{
|
||||
{sizeof("PPL file:") * 8, 0 * 16, screen_width - sizeof("PPL file:") * 8, 16},
|
||||
{sizeof("PPL file:") * 8, 0 * 16, screen_width - (int)sizeof("PPL file:") * 8, 16},
|
||||
""};
|
||||
|
||||
MenuView menu_view{};
|
||||
|
||||
+16
-16
@@ -60,29 +60,29 @@ class ProtoView : public View {
|
||||
"rx_protoview", app_settings::Mode::RX};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
{UI_POS_X(13), UI_POS_Y(0)}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
{UI_POS_X(15), UI_POS_Y(0)}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
{UI_POS_X(18), UI_POS_Y(0)}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
{UI_POS_X(21), UI_POS_Y(0), UI_POS_WIDTH(6), 4}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 0 * 16}};
|
||||
{UI_POS_X_RIGHT(2), UI_POS_Y(0)}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
nav_};
|
||||
|
||||
// need to seperate because label shift need to hide independently
|
||||
Labels label_zoom{
|
||||
{{0 * 8, 1 * 16}, "Zoom: ", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "Zoom: ", Theme::getInstance()->fg_light->foreground}};
|
||||
Labels label_shift{
|
||||
{{0 * 8, 2 * 16}, "Shift: ", Theme::getInstance()->fg_light->foreground}};
|
||||
{{UI_POS_X(0), UI_POS_Y(2)}, "Shift: ", Theme::getInstance()->fg_light->foreground}};
|
||||
|
||||
OptionsField options_zoom{
|
||||
{7 * 8, 1 * 16},
|
||||
{UI_POS_X(7), UI_POS_Y(1)},
|
||||
4,
|
||||
{{"1", 1},
|
||||
{"2", 2},
|
||||
@@ -96,22 +96,22 @@ class ProtoView : public View {
|
||||
{"1000", 1000}}};
|
||||
|
||||
NumberField number_shift{
|
||||
{7 * 8, 2 * 16},
|
||||
{UI_POS_X(7), UI_POS_Y(2)},
|
||||
5,
|
||||
{-MAXSIGNALBUFFER, MAXSIGNALBUFFER},
|
||||
1,
|
||||
' '};
|
||||
|
||||
Button button_reset{
|
||||
{screen_width - 12 * 8, 1 * 16, 96, 24},
|
||||
{UI_POS_X_RIGHT(12), UI_POS_Y(1), UI_POS_WIDTH(12), UI_POS_HEIGHT(1.5)},
|
||||
LanguageHelper::currentMessages[LANG_RESET]};
|
||||
|
||||
Button button_pause{
|
||||
{screen_width - 12 * 8, 1 * 16 + 24, 96, 24},
|
||||
{UI_POS_X_RIGHT(12), UI_POS_Y(2.5), UI_POS_WIDTH(12), UI_POS_HEIGHT(1.5)},
|
||||
LanguageHelper::currentMessages[LANG_PAUSE]};
|
||||
|
||||
Waveform waveform{
|
||||
{0, 8 * 8, 240, 50},
|
||||
{UI_POS_X(0), UI_POS_Y(4), UI_POS_MAXWIDTH, (UI_POS_HEIGHT_REMAINING(5) / 4) - 4},
|
||||
waveform_buffer,
|
||||
0,
|
||||
0,
|
||||
@@ -119,7 +119,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform2{
|
||||
{0, 8 * 8 + 55, 240, 50},
|
||||
{UI_POS_X(0), UI_POS_Y(4) + (UI_POS_HEIGHT_REMAINING(5) / 4), UI_POS_MAXWIDTH, (UI_POS_HEIGHT_REMAINING(5) / 4) - 4},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF],
|
||||
0,
|
||||
0,
|
||||
@@ -127,7 +127,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform3{
|
||||
{0, 8 * 8 + 110, 240, 50},
|
||||
{UI_POS_X(0), UI_POS_Y(4) + 2 * (UI_POS_HEIGHT_REMAINING(5) / 4), UI_POS_MAXWIDTH, (UI_POS_HEIGHT_REMAINING(5) / 4) - 4},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF * 2],
|
||||
0,
|
||||
0,
|
||||
@@ -135,7 +135,7 @@ class ProtoView : public View {
|
||||
Theme::getInstance()->fg_yellow->foreground};
|
||||
|
||||
Waveform waveform4{
|
||||
{0, 8 * 8 + 165, 240, 50},
|
||||
{UI_POS_X(0), UI_POS_Y(4) + 3 * (UI_POS_HEIGHT_REMAINING(5) / 4), UI_POS_MAXWIDTH, (UI_POS_HEIGHT_REMAINING(5) / 4) - 4},
|
||||
&waveform_buffer[MAXDRAWCNTPERWF * 3],
|
||||
0,
|
||||
0,
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ __attribute__((section(".external_app.app_random_password.application_informatio
|
||||
0x01,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::yellow().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
/*.menu_location = */ app_location_t::UTILITIES,
|
||||
/*.desired_menu_position = */ -1,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'F', 'R'},
|
||||
|
||||
@@ -203,7 +203,7 @@ class RandomPasswordView : public View {
|
||||
' '};
|
||||
|
||||
OptionsField field_method{
|
||||
{(screen_width / 2) + (sizeof("method:") - 1) * 8, 7 * 16 - 2},
|
||||
{(screen_width / 2) + (int)(sizeof("method:") - 1) * 8, 7 * 16 - 2},
|
||||
sizeof("R+L+R+H"),
|
||||
{{"R+L+R", Method::RADIO_LCG_ROLL},
|
||||
{"R+L+R+H", Method::RADIO_LCG_ROLL_HASH}}};
|
||||
|
||||
+7
-7
@@ -292,12 +292,12 @@ class RemoteAppView : public View {
|
||||
bool is_sending() const { return replay_thread_ != nullptr; }
|
||||
void show_error(const std::string& msg) const;
|
||||
|
||||
static constexpr Dim button_rows = 4;
|
||||
static constexpr Dim button_cols = 3;
|
||||
static constexpr uint8_t max_buttons = button_rows * button_cols;
|
||||
static constexpr Dim button_area_height = 200;
|
||||
static constexpr Dim button_width = screen_width / button_cols;
|
||||
static constexpr Dim button_height = button_area_height / button_rows;
|
||||
Dim button_rows = 4;
|
||||
Dim button_cols = 3;
|
||||
uint8_t max_buttons = button_rows * button_cols;
|
||||
Dim button_area_height = 200;
|
||||
Dim button_width = screen_width / button_cols;
|
||||
Dim button_height = button_area_height / button_rows;
|
||||
|
||||
// This value is mysterious... why?
|
||||
static constexpr uint32_t baseband_bandwidth = 2'500'000;
|
||||
@@ -328,7 +328,7 @@ class RemoteAppView : public View {
|
||||
bool ready_signal_{}; // Used to signal ReplayThread ready.
|
||||
|
||||
TextField field_title{
|
||||
{0 * 8, 0 * 16 + 2, 30 * 8, 1 * 16},
|
||||
{0 * 8, 0 * 16 + 2, screen_width, 1 * 16},
|
||||
{}};
|
||||
|
||||
TransmitterView2 tx_view{
|
||||
|
||||
+2
-2
@@ -217,7 +217,7 @@ class ScannerView : public View {
|
||||
|
||||
NumberField field_lock_wait{
|
||||
// Signal-Lost wait timer - time to wait before moving on after losing signal lock
|
||||
{28 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, 1 * 16},
|
||||
2,
|
||||
{0, 99},
|
||||
1,
|
||||
@@ -238,7 +238,7 @@ class ScannerView : public View {
|
||||
};
|
||||
|
||||
Text text_current_desc{
|
||||
{0, 4 * 16, 240 - 6 * 8, 16},
|
||||
{0, 4 * 16, screen_width - 6 * 8, 16},
|
||||
};
|
||||
|
||||
BigFrequency big_display{
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ class WipeSDView : public View {
|
||||
{2 * 8, 19 * 8, 26 * 8, 24}};
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class ShoppingCartLock : public View {
|
||||
void restart_playback();
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 0, 240, 150},
|
||||
{0, 0, screen_width, 150},
|
||||
true};
|
||||
|
||||
Text text_empty{
|
||||
|
||||
+33
-60
@@ -10,81 +10,54 @@
|
||||
|
||||
namespace ui::external_app::snake {
|
||||
|
||||
Ticker game_timer;
|
||||
|
||||
int snake_x[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_y[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_length = 1;
|
||||
int snake_dx = 1;
|
||||
int snake_dy = 0;
|
||||
int food_x, food_y;
|
||||
int score = 0;
|
||||
int game_state = STATE_MENU;
|
||||
bool initialized = false;
|
||||
|
||||
const Color pp_colors[] = {
|
||||
Color::white(),
|
||||
Color::blue(),
|
||||
Color::yellow(),
|
||||
Color::purple(),
|
||||
Color::green(),
|
||||
Color::red(),
|
||||
Color::magenta(),
|
||||
Color::orange(),
|
||||
Color::black(),
|
||||
};
|
||||
|
||||
Painter painter;
|
||||
|
||||
bool but_RIGHT = false;
|
||||
bool but_LEFT = false;
|
||||
bool but_SELECT = false;
|
||||
|
||||
static Callback game_update_callback = nullptr;
|
||||
static uint32_t game_update_timeout = 0;
|
||||
static uint32_t game_update_counter = 0;
|
||||
|
||||
void cls() {
|
||||
void SnakeView::cls() {
|
||||
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
||||
}
|
||||
|
||||
void background(int color) {
|
||||
void SnakeView::background(int color) {
|
||||
(void)color;
|
||||
}
|
||||
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
void SnakeView::fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
}
|
||||
|
||||
void rect(int x1, int y1, int x2, int y2, int color) {
|
||||
void SnakeView::rect(int x1, int y1, int x2, int y2, int color) {
|
||||
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
|
||||
}
|
||||
|
||||
void check_game_timer() {
|
||||
void SnakeView::check_game_timer() {
|
||||
if (game_update_callback) {
|
||||
if (++game_update_counter >= game_update_timeout) {
|
||||
game_update_counter = 0;
|
||||
game_update_callback();
|
||||
game_timer_check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ticker::attach(Callback func, double delay_sec) {
|
||||
game_update_callback = func;
|
||||
void SnakeView::attach(double delay_sec) {
|
||||
game_update_callback = true;
|
||||
game_update_timeout = delay_sec * 60;
|
||||
}
|
||||
|
||||
void Ticker::detach() {
|
||||
game_update_callback = nullptr;
|
||||
void SnakeView::detach() {
|
||||
game_update_callback = false;
|
||||
}
|
||||
|
||||
void game_timer_check() {
|
||||
void SnakeView::game_timer_check() {
|
||||
if (game_state == STATE_PLAYING) {
|
||||
update_game();
|
||||
}
|
||||
}
|
||||
|
||||
void init_game() {
|
||||
void SnakeView::init_game() {
|
||||
SCREEN_WIDTH = screen_width;
|
||||
SCREEN_HEIGHT = screen_height;
|
||||
GAME_AREA_HEIGHT = (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2);
|
||||
GRID_WIDTH = ((SCREEN_WIDTH - 2) / SNAKE_SIZE);
|
||||
GRID_HEIGHT = (GAME_AREA_HEIGHT / SNAKE_SIZE);
|
||||
snake_x.resize(GRID_WIDTH * GRID_HEIGHT);
|
||||
snake_y.resize(GRID_WIDTH * GRID_HEIGHT);
|
||||
snake_x[0] = GRID_WIDTH / 2;
|
||||
snake_y[0] = GRID_HEIGHT / 2;
|
||||
snake_length = 1;
|
||||
@@ -99,7 +72,7 @@ void init_game() {
|
||||
}
|
||||
}
|
||||
|
||||
void spawn_food() {
|
||||
void SnakeView::spawn_food() {
|
||||
bool valid;
|
||||
do {
|
||||
food_x = rand() % GRID_WIDTH;
|
||||
@@ -114,7 +87,7 @@ void spawn_food() {
|
||||
} while (!valid);
|
||||
}
|
||||
|
||||
void update_game() {
|
||||
void SnakeView::update_game() {
|
||||
int new_x = snake_x[0] + snake_dx;
|
||||
int new_y = snake_y[0] + snake_dy;
|
||||
bool ate_food = (new_x == food_x && new_y == food_y);
|
||||
@@ -152,7 +125,7 @@ void update_game() {
|
||||
}
|
||||
}
|
||||
|
||||
bool check_collision() {
|
||||
bool SnakeView::check_collision() {
|
||||
if (snake_x[0] < 0 || snake_x[0] >= GRID_WIDTH || snake_y[0] < 0 || snake_y[0] >= GRID_HEIGHT) {
|
||||
return true;
|
||||
}
|
||||
@@ -164,7 +137,7 @@ bool check_collision() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw_screen() {
|
||||
void SnakeView::draw_screen() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
draw_borders();
|
||||
@@ -173,44 +146,44 @@ void draw_screen() {
|
||||
draw_score();
|
||||
}
|
||||
|
||||
void draw_snake() {
|
||||
void SnakeView::draw_snake() {
|
||||
fillrect(1 + snake_x[0] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE,
|
||||
1 + snake_x[0] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[0] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE);
|
||||
}
|
||||
|
||||
void draw_full_snake() {
|
||||
void SnakeView::draw_full_snake() {
|
||||
for (int i = 0; i < snake_length; i++) {
|
||||
fillrect(1 + snake_x[i] * SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE,
|
||||
1 + snake_x[i] * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + snake_y[i] * SNAKE_SIZE + SNAKE_SIZE, COLOR_SNAKE);
|
||||
}
|
||||
}
|
||||
|
||||
void erase_tail(int x, int y) {
|
||||
void SnakeView::erase_tail(int x, int y) {
|
||||
fillrect(1 + x * SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE,
|
||||
1 + x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND);
|
||||
}
|
||||
|
||||
void draw_food() {
|
||||
void SnakeView::draw_food() {
|
||||
fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE,
|
||||
1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_FOOD);
|
||||
}
|
||||
|
||||
void erase_food() {
|
||||
void SnakeView::erase_food() {
|
||||
fillrect(1 + food_x * SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE,
|
||||
1 + food_x * SNAKE_SIZE + SNAKE_SIZE, GAME_AREA_TOP + food_y * SNAKE_SIZE + SNAKE_SIZE, COLOR_BACKGROUND);
|
||||
}
|
||||
|
||||
void draw_score() {
|
||||
void SnakeView::draw_score() {
|
||||
auto style = *ui::Theme::getInstance()->fg_blue;
|
||||
painter.draw_string({5, 5}, style, "Score: " + std::to_string(score));
|
||||
}
|
||||
|
||||
void draw_borders() {
|
||||
void SnakeView::draw_borders() {
|
||||
rect(0, GAME_AREA_TOP - 1, SCREEN_WIDTH, GAME_AREA_TOP, COLOR_BORDER);
|
||||
rect(0, GAME_AREA_TOP, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BORDER);
|
||||
}
|
||||
|
||||
void show_menu() {
|
||||
void SnakeView::show_menu() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
auto style_yellow = *ui::Theme::getInstance()->fg_yellow;
|
||||
@@ -223,7 +196,7 @@ void show_menu() {
|
||||
painter.draw_string({15, 240}, style_green, "** PRESS SELECT TO START **");
|
||||
}
|
||||
|
||||
void show_game_over() {
|
||||
void SnakeView::show_game_over() {
|
||||
cls();
|
||||
background(COLOR_BACKGROUND);
|
||||
auto style_red = *ui::Theme::getInstance()->fg_red;
|
||||
@@ -238,7 +211,7 @@ void show_game_over() {
|
||||
SnakeView::SnakeView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children({&dummy});
|
||||
game_timer.attach(&game_timer_check, 1.0 / 5.0);
|
||||
attach(1.0 / 5.0);
|
||||
}
|
||||
|
||||
void SnakeView::on_show() {
|
||||
|
||||
+57
-56
@@ -32,36 +32,11 @@ enum {
|
||||
Black,
|
||||
};
|
||||
|
||||
extern const Color pp_colors[];
|
||||
extern Painter painter;
|
||||
extern bool but_RIGHT;
|
||||
extern bool but_LEFT;
|
||||
extern bool but_SELECT;
|
||||
|
||||
void cls();
|
||||
void background(int color);
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color);
|
||||
void rect(int x1, int y1, int x2, int y2, int color);
|
||||
|
||||
#define wait(x) chThdSleepMilliseconds(x * 1000)
|
||||
|
||||
using Callback = void (*)(void);
|
||||
|
||||
class Ticker {
|
||||
public:
|
||||
Ticker() = default;
|
||||
void attach(Callback func, double delay_sec);
|
||||
void detach();
|
||||
};
|
||||
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 320
|
||||
#define SNAKE_SIZE 10
|
||||
#define INFO_BAR_HEIGHT 25
|
||||
#define GAME_AREA_TOP (INFO_BAR_HEIGHT + 1)
|
||||
#define GAME_AREA_HEIGHT (SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2)
|
||||
#define GRID_WIDTH ((SCREEN_WIDTH - 2) / SNAKE_SIZE)
|
||||
#define GRID_HEIGHT (GAME_AREA_HEIGHT / SNAKE_SIZE)
|
||||
#define STATE_MENU 0
|
||||
#define STATE_PLAYING 1
|
||||
#define STATE_GAME_OVER 2
|
||||
@@ -71,35 +46,6 @@ class Ticker {
|
||||
#define COLOR_FOOD Red
|
||||
#define COLOR_BORDER White
|
||||
|
||||
extern Ticker game_timer;
|
||||
|
||||
extern int snake_x[GRID_WIDTH * GRID_HEIGHT];
|
||||
extern int snake_y[GRID_WIDTH * GRID_HEIGHT];
|
||||
extern int snake_length;
|
||||
extern int snake_dx;
|
||||
extern int snake_dy;
|
||||
extern int food_x;
|
||||
extern int food_y;
|
||||
extern int score;
|
||||
extern int game_state;
|
||||
extern bool initialized;
|
||||
|
||||
void game_timer_check();
|
||||
void init_game();
|
||||
void update_game();
|
||||
void draw_screen();
|
||||
void draw_snake();
|
||||
void draw_full_snake();
|
||||
void erase_tail(int x, int y);
|
||||
void draw_food();
|
||||
void erase_food();
|
||||
void draw_score();
|
||||
void draw_borders();
|
||||
void spawn_food();
|
||||
bool check_collision();
|
||||
void show_menu();
|
||||
void show_game_over();
|
||||
|
||||
class SnakeView : public View {
|
||||
public:
|
||||
SnakeView(NavigationView& nav);
|
||||
@@ -112,12 +58,67 @@ class SnakeView : public View {
|
||||
void frame_sync();
|
||||
bool on_key(KeyEvent key) override;
|
||||
|
||||
void cls();
|
||||
void background(int color);
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color);
|
||||
void rect(int x1, int y1, int x2, int y2, int color);
|
||||
void game_timer_check();
|
||||
void init_game();
|
||||
void update_game();
|
||||
void draw_screen();
|
||||
void draw_snake();
|
||||
void draw_full_snake();
|
||||
void erase_tail(int x, int y);
|
||||
void draw_food();
|
||||
void erase_food();
|
||||
void draw_score();
|
||||
void draw_borders();
|
||||
void spawn_food();
|
||||
bool check_collision();
|
||||
void show_menu();
|
||||
void show_game_over();
|
||||
void check_game_timer();
|
||||
|
||||
void attach(double delay_sec);
|
||||
void detach();
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
const Color pp_colors[9] = {
|
||||
Color::white(),
|
||||
Color::blue(),
|
||||
Color::yellow(),
|
||||
Color::purple(),
|
||||
Color::green(),
|
||||
Color::red(),
|
||||
Color::magenta(),
|
||||
Color::orange(),
|
||||
Color::black(),
|
||||
};
|
||||
NavigationView& nav_;
|
||||
Painter painter{};
|
||||
|
||||
std::vector<int> snake_x{}; //[GRID_WIDTH * GRID_HEIGHT];
|
||||
std::vector<int> snake_y{}; //[GRID_WIDTH * GRID_HEIGHT];
|
||||
int snake_length = 1;
|
||||
int snake_dx = 1;
|
||||
int snake_dy = 0;
|
||||
int food_x = 0, food_y = 0;
|
||||
int score = 0;
|
||||
int game_state = STATE_MENU;
|
||||
bool initialized = false;
|
||||
|
||||
int SCREEN_WIDTH = 0;
|
||||
int SCREEN_HEIGHT = 0;
|
||||
int GAME_AREA_HEIGHT = 0; //(SCREEN_HEIGHT - INFO_BAR_HEIGHT - 2);
|
||||
int GRID_WIDTH = 0; // ((SCREEN_WIDTH - 2) / SNAKE_SIZE);
|
||||
int GRID_HEIGHT = 0; //(GAME_AREA_HEIGHT / SNAKE_SIZE);
|
||||
|
||||
bool game_update_callback = false;
|
||||
double game_update_timeout = 0;
|
||||
uint32_t game_update_counter = 0;
|
||||
|
||||
Button dummy{
|
||||
{240, 0, 0, 0},
|
||||
{screen_width, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
||||
@@ -55,7 +55,7 @@ SpectrumPainterView::SpectrumPainterView(
|
||||
&field_pause,
|
||||
});
|
||||
|
||||
Rect view_rect = {0, 3 * 8, 240, 80};
|
||||
Rect view_rect = {0, 3 * 8, screen_width, 80};
|
||||
input_image.set_parent_rect(view_rect);
|
||||
input_text.set_parent_rect(view_rect);
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ class SpectrumPainterView : public View {
|
||||
|
||||
static constexpr int32_t footer_location = 15 * 16 + 8;
|
||||
ProgressBar progressbar{
|
||||
{4, footer_location - 16, 240 - 8, 16}};
|
||||
{4, footer_location - 16, screen_width - 8, 16}};
|
||||
|
||||
Labels labels{
|
||||
{{10 * 8, footer_location + 1 * 16}, "GAIN A:", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -121,7 +121,7 @@ class SpectrumPainterView : public View {
|
||||
true};
|
||||
|
||||
ImageButton button_play{
|
||||
{28 * 8, footer_location + 1 * 16, 2 * 8, 1 * 16},
|
||||
{screen_width - 2 * 8, footer_location + 1 * 16, 2 * 8, 1 * 16},
|
||||
&bitmap_play,
|
||||
Theme::getInstance()->fg_green->foreground,
|
||||
Theme::getInstance()->fg_green->background};
|
||||
|
||||
@@ -244,12 +244,12 @@ std::vector<uint8_t> SpectrumInputImageView::get_line(uint16_t y) {
|
||||
|
||||
void SpectrumInputImageView::paint(Painter& painter) {
|
||||
painter.fill_rectangle(
|
||||
{{0, 40}, {240, 204}},
|
||||
{{0, 40}, {screen_width, 204}},
|
||||
style().background);
|
||||
|
||||
if (!painted) {
|
||||
// This is very slow for big pictures. Do only once.
|
||||
this->drawBMP_scaled({{0, 40}, {240, 160}}, this->file);
|
||||
this->drawBMP_scaled({{0, 40}, {screen_width, 160}}, this->file);
|
||||
painted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class SpectrumInputImageView : public View {
|
||||
uint32_t data_start{0};
|
||||
|
||||
Button button_load_image{
|
||||
{0 * 8, 11 * 16 - 4, 30 * 8, 28},
|
||||
{0 * 8, 11 * 16 - 4, screen_width, 28},
|
||||
"Load Image ..."};
|
||||
|
||||
bool drawBMP_scaled(const ui::Rect r, const std::string file);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user