Compare commits

..

34 Commits

Author SHA1 Message Date
Totoo c1bf2620c7 Bt namespam (#2009)
* Add random names
2024-03-18 21:45:45 +01:00
Mark Thompson 8383363e74 Preserve radio mode when updating iq_tx_phase_cal (#2008) 2024-03-18 21:45:02 +01:00
Alexandros Andreou 6e34343bde added all and all-safe attack types to blespam (#2003) 2024-03-18 09:13:10 +01:00
gullradriel 01e4ff65a2 fix butngrid/capture and fix contributor name (#1995)
* fixing contributor name

* used clear instead of swap

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2024-03-16 00:39:34 +08:00
Totoo 9e40e38f07 Record gps lat, lon, satinuse from recorder app if there was gps signal. (#1992)
* Record gps lat, lon, satinuse from recorder app if there was gps signal.

* Add _GEO to filename that has geotag
2024-03-15 21:56:20 +08:00
not tre mann 181624daf1 lambda the flash util menu add item code (#1993)
* lambda the flash util menu add code

* clean up
2024-03-14 22:56:55 -05:00
Mark Thompson f0614c882b File manager "Clean" button tweaks (#1990)
* File Manager "clean" button tweaks

* Add files via upload
2024-03-13 22:42:40 +01:00
not tre mann 14f42d1fe8 support "clean" files (#1983)
* init for clean files
* textual
* icons position
2024-03-13 18:06:14 +01:00
Mark Thompson 999f9e2ded Fix #1982 (enable DMA interrupt for all apps) (#1987) 2024-03-13 16:57:35 +01:00
Mark Thompson 61dc8a0225 Disabled unused baseband "no-op" process (#1986) 2024-03-13 16:08:52 +01:00
Mark Thompson 0b2d5f75cc Start audio DMA only in apps that use audio (#1982)
* Start audio DMA only in apps that use audio
* Rename main.cpp to main.cpp.unuse
* shrink_tx_buffer fix for transfers_per_buffer==1 scenario
2024-03-13 16:07:44 +01:00
Erwin Ried 3c489e1a81 Steamlining the warning (#1984)
I think it is enough to note nobody should pay for the download
2024-03-13 19:30:05 +08:00
gullradriel 910fd82051 freqman: limiting description size to 30, and minor fix (#1977)
* Limiting description size to 30 as it was documented before

* cosmetic adjustement

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2024-03-11 16:40:47 +01:00
gullradriel 866e12fbc5 added RXIQCALC (#1974)
Co-authored-by: GullCode <gullradriel@hotmail.com>
2024-03-10 23:25:18 +01:00
Mark Thompson ccd71d9593 Set iq_phase_cal in radio when starting SPEC mode (#1972) 2024-03-10 20:50:48 +01:00
Mark Thompson e9b9ba4602 Deallocate menu buttons to save memory (#1971)
* Deallocate hidden menu buttons
* Added Copyright
* Added comments
2024-03-10 20:49:36 +01:00
gullradriel 986e37a3c9 fix unused warning (#1970) 2024-03-10 20:05:05 +01:00
gullradriel 2ac36d2d0b Level app: coloration of RxSat value (#1969) 2024-03-10 18:29:21 +01:00
Mark Thompson 3b79549129 Added enums for recon_config bits (#1965) 2024-03-10 08:30:05 +01:00
gullradriel 160a778104 Recon repeat auto recorded file mode (#1960)
* added everything needed to have a repeated file mode option to keep or delete files

* automatic filename for keep file

* fixing restart after replay

* fixed auto record replay/repeat restart

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2024-03-10 08:45:54 +08:00
Mark Thompson e496f8ecc2 Eliminate unnecessary NumberField to save code space (#1964)
* Eliminate extra NumberField to save code space

* Clang
2024-03-09 17:36:48 -06:00
Brumi-2021 9d8132978f Adding Rx IQ error phase CAL to SPEC Audio_App (#1963) 2024-03-09 23:46:38 +01:00
Mark Thompson 73c29f666f Commented out Debug -> Memory Usage app (#1962) 2024-03-09 22:03:07 +01:00
Mark Thompson d895c9fa91 Show true M0 free heap space in DFU overlay (#1961) 2024-03-09 21:39:06 +01:00
gullradriel b5e66387c3 Rxsat in Level app (#1959)
* added Rx Saturation

* testing reducing values to uint8_t

* clang format

* refactorisation

* cleanings

* cleanings

* set back request_m4_performance_counter to zero on app exit

---------

Co-authored-by: GullCode <gullradriel@hotmail.com>
2024-03-09 22:26:56 +08:00
Mark Thompson 1fbfdbccf8 Remove unused text_info widget (#1955) 2024-03-08 01:29:13 +08:00
Totoo 2648f18b12 External sensor tester app (#1949)
* added tilt
* added extsensors app
* added icon
* Added EnvironmentData to ExtSensor app and message.hpp
* Added gotenv command
2024-03-07 17:22:24 +01:00
Mark Thompson 908c0e2cd5 Fix compiler warning (#1952) 2024-03-07 17:18:08 +01:00
Mark Thompson 4f3530db5e Update FPV_ANALOG.TXT (#1951)
* Include FPV in freq description

* Added comment referencing source of this data
2024-03-08 00:00:53 +08:00
not tre mann 73137891c4 change sun bitmap to make it more like a sun (#1946) 2024-03-07 07:50:49 +01:00
not tre mann c28087ac44 cheat code protect in pacman app (#1945) 2024-03-07 07:49:17 +01:00
Totoo 9e9dd3a521 Dynamic usb buffer fill for screenframeshort (#1935)
* fully fill usb serial buffer
* Update usb_serial_shell.cpp
* Added a comment, to trigger wf
2024-03-07 07:42:58 +01:00
Dima Danylevskyi 3bf689f339 Add FPV analog frequenies to FREQMAN (#1940) 2024-03-07 07:37:41 +01:00
Erwin Ried 86c326ef12 Update README.md (#1937)
Adding a warning
2024-02-26 17:50:11 +01:00
87 changed files with 1433 additions and 372 deletions
+4
View File
@@ -76,3 +76,7 @@ venv/
# Other
*.bak
# generated bitmap arr file
# TODO: generate bitmap during build, since we use python during build anyway, lemme know if this is a bad idea @zxkmm
/firmware/tools/bitmap.hpp
+3 -2
View File
@@ -1,5 +1,6 @@
> [!IMPORTANT]
> this repository **has just been moved** from my personal GitHub [eried/portapack-mayhem](https://github.com/eried/portapack-mayhem) to an organization: [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware). Please keep this in mind to **update your links** accordingly.
> [!WARNING]
> __IF YOU'VE PAID FOR MAYHEM OR ANY PREPACKAGED PACKAGES, YOU'RE BEING SCAMMED.__
> The only legitimate link leading to our repositories is the organization [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware).
# PortaPack Mayhem
+26 -4
View File
@@ -30,6 +30,7 @@
#include "string_format.hpp"
#include "ui_freqman.hpp"
#include "utility.hpp"
#include "radio.hpp"
using namespace portapack;
using namespace tonekey;
@@ -112,10 +113,14 @@ SPECOptionsView::SPECOptionsView(
: View{parent_rect} {
set_style(style);
add_children({&label_config,
&options_config,
&text_speed,
&field_speed});
add_children({
&label_config,
&options_config,
&text_speed,
&field_speed,
&text_rx_cal,
&field_rx_iq_phase_cal,
});
options_config.set_selected_index(view->get_spec_bw_index());
options_config.on_change = [this, view](size_t n, OptionsField::value_t bw) {
@@ -126,6 +131,14 @@ SPECOptionsView::SPECOptionsView(
field_speed.on_change = [this, view](int32_t v) {
view->set_spec_trigger(v);
};
field_rx_iq_phase_cal.set_range(0, hackrf_r9 ? 63 : 31); // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31]
field_rx_iq_phase_cal.set_value(view->get_spec_iq_phase_calibration_value()); // using accessor function of AnalogAudioView to read iq_phase_calibration_value from rx_audio.ini
field_rx_iq_phase_cal.on_change = [this, view](int32_t v) {
view->set_spec_iq_phase_calibration_value(v); // using accessor function of AnalogAudioView to write inside SPEC submenu, register value to max283x and save it to rx_audio.ini
};
view->set_spec_iq_phase_calibration_value(view->get_spec_iq_phase_calibration_value()); // initialize iq_phase_calibration in radio
}
/* AnalogAudioView *******************************************************/
@@ -213,6 +226,15 @@ void AnalogAudioView::set_spec_bw(size_t index, uint32_t bw) {
receiver_model.set_baseband_bandwidth(bw / 2);
}
uint8_t AnalogAudioView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
return iq_phase_calibration_value;
}
void AnalogAudioView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // define accessor functions
iq_phase_calibration_value = cal_value;
radio::set_rx_max283x_iq_phase_calibration(iq_phase_calibration_value);
}
uint16_t AnalogAudioView::get_spec_trigger() {
return spec_trigger;
}
+20 -2
View File
@@ -133,6 +133,16 @@ class SPECOptionsView : public View {
1,
' ',
};
Text text_rx_cal{
{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},
2,
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
1,
' ',
};
};
class AnalogAudioView : public View {
@@ -152,14 +162,22 @@ class AnalogAudioView : public View {
uint16_t get_spec_trigger();
void set_spec_trigger(uint16_t trigger);
uint8_t get_spec_iq_phase_calibration_value();
void set_spec_iq_phase_calibration_value(uint8_t cal_value);
private:
static constexpr ui::Dim header_height = 3 * 16;
NavigationView& nav_;
RxRadioState radio_state_{};
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
app_settings::SettingsManager settings_{
"rx_audio", app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency};
"rx_audio",
app_settings::Mode::RX,
app_settings::Options::UseGlobalTargetFrequency,
{
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
}};
const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16};
const Rect nbfm_view_rect{0 * 8, 1 * 16, 18 * 8, 1 * 16};
@@ -13,7 +13,7 @@ AboutView::AboutView(NavigationView& nav) {
}
void AboutView::update() {
if (++timer > 200) {
if (++timer > 400) {
timer = 0;
switch (++frame) {
@@ -23,7 +23,7 @@ void AboutView::update() {
console.writeln(STR_COLOR_DARK_YELLOW "Mayhem:");
console.writeln("eried,euquiq,gregoryfenton");
console.writeln("johnelder,jwetzell,nnemanjan00");
console.writeln("N0vaPixel,klockee,GullCode");
console.writeln("N0vaPixel,klockee,gullradriel");
console.writeln("jamesshao8,ITAxReal,rascafr");
console.writeln("mcules,dqs105,strijar");
console.writeln("zhang00963,RedFox-Fr,aldude999");
+34 -22
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* Copyright (C) 2024 u-foka
*
* This file is part of PortaPack.
*
@@ -445,14 +446,19 @@ void DebugControlsView::focus() {
/* DebugPeripheralsMenuView **********************************************/
DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav)
: nav_(nav) {
set_max_rows(2); // allow wider buttons
}
void DebugPeripheralsMenuView::on_populate() {
const char* max283x = hackrf_r9 ? "MAX2839" : "MAX2837";
const char* si5351x = hackrf_r9 ? "Si5351A" : "Si5351C";
add_items({
{"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }},
{max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push<RegistersView>(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }},
{si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
{audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
{"RFFC5072", ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }},
{max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this, max283x]() { nav_.push<RegistersView>(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }},
{si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push<RegistersView>(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }},
{audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this]() { nav_.push<RegistersView>(audio::debug::codec_name(), RegistersWidgetConfig{CT_AUDIO, audio::debug::reg_count(), audio::debug::reg_count(), audio::debug::reg_bits()}); }},
});
set_max_rows(2); // allow wider buttons
}
@@ -468,32 +474,38 @@ DebugReboot::DebugReboot(NavigationView& nav) {
__WFE();
}
void DebugReboot::on_populate() {
}
/* DebugMenuView *********************************************************/
DebugMenuView::DebugMenuView(NavigationView& nav) {
DebugMenuView::DebugMenuView(NavigationView& nav)
: nav_(nav) {
set_max_rows(2); // allow wider buttons
}
void DebugMenuView::on_populate() {
if (portapack::persistent_memory::show_gui_return_icon()) {
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_items({
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav]() { nav.push<DebugControlsView>(); }},
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { portapack::persistent_memory::debug_dump(); }},
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { stack_dump(); }},
{"Memory Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryDumpView>(); }},
{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push<DebugPeripheralsMenuView>(); }},
{"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
//{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
{"Reboot", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<DebugReboot>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SDCardDebugView>(); }},
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
{"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<DebugScreenTest>(); }},
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [this]() { nav_.push<DebugControlsView>(); }},
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { portapack::persistent_memory::debug_dump(); }},
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { stack_dump(); }},
{"Memory Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push<DebugMemoryDumpView>(); }},
//{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push<DebugMemoryView>(); }},
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [this]() { nav_.push<DebugPeripheralsMenuView>(); }},
{"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push<DebugPmemView>(); }},
//{ "Radio State", ui::Color::white(), nullptr, [this](){ nav_.push<NotImplementedView>(); } },
{"Reboot", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<DebugReboot>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push<SDCardDebugView>(); }},
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [this]() { nav_.push<TemperatureView>(); }},
{"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [this]() { nav_.push<DebugScreenTest>(); }},
});
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav)) {
for (auto const& gridItem : ExternalItemsMenuLoader::load_external_items(app_location_t::DEBUG, nav_)) {
add_item(gridItem);
};
set_max_rows(2); // allow wider buttons
}
/* DebugMemoryDumpView *********************************************************/
+12
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* Copyright (C) 2024 u-foka
*
* This file is part of PortaPack.
*
@@ -422,17 +423,28 @@ class DebugPeripheralsMenuView : public BtnGridView {
public:
DebugPeripheralsMenuView(NavigationView& nav);
std::string title() const override { return "Peripherals"; };
private:
NavigationView& nav_;
void on_populate() override;
};
class DebugReboot : public BtnGridView {
public:
DebugReboot(NavigationView& nav);
private:
void on_populate() override;
};
class DebugMenuView : public BtnGridView {
public:
DebugMenuView(NavigationView& nav);
std::string title() const override { return "Debug"; };
private:
NavigationView& nav_;
void on_populate() override;
};
} /* namespace ui */
+15 -9
View File
@@ -38,23 +38,29 @@ DfuMenu::DfuMenu(NavigationView& nav)
&text_info_line_5,
&text_info_line_6,
&text_info_line_7,
&text_info_line_8});
&text_info_line_8,
&text_info_line_9,
&text_info_line_10});
}
void DfuMenu::paint(Painter& painter) {
auto utilisation = get_cpu_utilisation_in_percent();
size_t m0_fragmented_free_space = 0;
const auto m0_fragments = chHeapStatus(NULL, &m0_fragmented_free_space);
text_info_line_1.set(to_string_dec_uint(chCoreStatus(), 6));
text_info_line_2.set(to_string_dec_uint((uint32_t)get_free_stack_space(), 6));
text_info_line_3.set(to_string_dec_uint(utilisation, 6));
text_info_line_4.set(to_string_dec_uint(shared_memory.m4_heap_usage, 6));
text_info_line_5.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
text_info_line_6.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
text_info_line_8.set(to_string_dec_uint(chTimeNow() / 1000, 6));
text_info_line_2.set(to_string_dec_uint(m0_fragmented_free_space, 6));
text_info_line_3.set(to_string_dec_uint(m0_fragments, 6));
text_info_line_4.set(to_string_dec_uint((uint32_t)get_free_stack_space(), 6));
text_info_line_5.set(to_string_dec_uint(utilisation, 6));
text_info_line_6.set(to_string_dec_uint(shared_memory.m4_heap_usage, 6));
text_info_line_7.set(to_string_dec_uint(shared_memory.m4_stack_usage, 6));
text_info_line_8.set(to_string_dec_uint(shared_memory.m4_performance_counter, 6));
text_info_line_9.set(to_string_dec_uint(shared_memory.m4_buffer_missed, 6));
text_info_line_10.set(to_string_dec_uint(chTimeNow() / 1000, 6));
constexpr auto margin = 5;
constexpr auto lines = 8 + 2;
constexpr auto lines = 10 + 2;
painter.fill_rectangle(
{{6 * CHARACTER_WIDTH - margin, 3 * LINE_HEIGHT - margin},
+12 -8
View File
@@ -49,14 +49,16 @@ class DfuMenu : public View {
Text text_head{{6 * CHARACTER_WIDTH, 3 * LINE_HEIGHT, 11 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, "Performance"};
Labels labels{
{{6 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "M0 heap:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "M0 stack:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "M0 cpu %:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 8 * LINE_HEIGHT}, "M4 heap:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 9 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 10 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}};
{{6 * CHARACTER_WIDTH, 5 * LINE_HEIGHT}, "M0 core:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 6 * LINE_HEIGHT}, "M0 heap:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 7 * LINE_HEIGHT}, "M0 frags:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 8 * LINE_HEIGHT}, "M0 stack:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 9 * LINE_HEIGHT}, "M0 cpu %:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 10 * LINE_HEIGHT}, "M4 heap:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 11 * LINE_HEIGHT}, "M4 stack:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 12 * LINE_HEIGHT}, "M4 cpu %:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 13 * LINE_HEIGHT}, "M4 miss:", Color::dark_cyan()},
{{6 * CHARACTER_WIDTH, 14 * LINE_HEIGHT}, "uptime:", Color::dark_cyan()}};
Text text_info_line_1{{15 * CHARACTER_WIDTH, 5 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_2{{15 * CHARACTER_WIDTH, 6 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
@@ -66,6 +68,8 @@ class DfuMenu : public View {
Text text_info_line_6{{15 * CHARACTER_WIDTH, 10 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_7{{15 * CHARACTER_WIDTH, 11 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_8{{15 * CHARACTER_WIDTH, 12 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_9{{15 * CHARACTER_WIDTH, 13 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
Text text_info_line_10{{15 * CHARACTER_WIDTH, 14 * LINE_HEIGHT, 6 * CHARACTER_WIDTH, 1 * LINE_HEIGHT}, ""};
};
class DfuMenu2 : public View {
+33 -1
View File
@@ -402,6 +402,7 @@ void FileSaveView::refresh_widgets() {
void FileManagerView::refresh_widgets(const bool v) {
button_rename.hidden(v);
button_delete.hidden(v);
button_clean.hidden(v);
button_cut.hidden(v);
button_copy.hidden(v);
button_paste.hidden(v);
@@ -449,7 +450,7 @@ void FileManagerView::on_rename(std::string_view hint) {
void FileManagerView::on_delete() {
if (is_directory(get_selected_full_path()) && !is_empty_directory(get_selected_full_path())) {
nav_.display_modal("Delete", "Directory not empty!");
nav_.display_modal("Delete", " Folder is not empty;\n Use \"Clean\" button to\n empty it first.");
return;
}
@@ -474,6 +475,31 @@ void FileManagerView::on_delete() {
});
}
void FileManagerView::on_clean() {
if (is_empty_directory(get_selected_full_path())) {
nav_.display_modal("Clean", "Folder is Empty;\nUse \"Delete\" button instead\nof \"Clean\" button to delete\nit.");
return;
}
auto path_name = is_directory(get_selected_full_path()) ? get_selected_full_path() : get_selected_full_path().parent_path();
// selected either a single file (delete files in this directory) or a directory that is not empty (del sub files)
nav_.push<ModalMessageView>(
"Clean", " ALL FILES in this folder\n (excluding sub-folders)\n will be DELETED!\n\n Delete all files?", YESNO,
[this, path_name](bool choice) {
if (choice) {
std::vector<std::filesystem::path> file_list;
file_list = scan_root_files(path_name, u"*");
for (const auto& file_name : file_list) {
std::filesystem::path current_full_path = path_name / file_name;
delete_file(current_full_path);
}
reload_current();
}
});
}
void FileManagerView::on_new_dir() {
name_buffer = "";
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) {
@@ -560,6 +586,7 @@ FileManagerView::FileManagerView(
&text_date,
&button_rename,
&button_delete,
&button_clean,
&button_cut,
&button_copy,
&button_paste,
@@ -606,6 +633,11 @@ FileManagerView::FileManagerView(
on_delete();
};
button_clean.on_select = [this]() {
if (selected_is_valid())
on_clean();
};
button_cut.on_select = [this]() {
if (selected_is_valid() && !get_selected_entry().is_directory) {
clipboard_path = get_selected_full_path();
+13 -4
View File
@@ -207,6 +207,7 @@ class FileManagerView : public FileManBaseView {
void refresh_widgets(const bool v);
void on_rename(std::string_view hint);
void on_delete();
void on_clean();
void on_paste();
void on_new_dir();
void on_new_file();
@@ -227,11 +228,17 @@ class FileManagerView : public FileManBaseView {
Color::dark_blue()};
NewButton button_delete{
{4 * 8, 29 * 8, 4 * 8, 32},
{9 * 8, 34 * 8, 4 * 8, 32},
{},
&bitmap_icon_trash,
Color::red()};
NewButton button_clean{
{13 * 8, 34 * 8, 4 * 8, 32},
{},
&bitmap_icon_clean,
Color::red()};
NewButton button_cut{
{9 * 8, 29 * 8, 4 * 8, 32},
{},
@@ -269,20 +276,22 @@ class FileManagerView : public FileManBaseView {
Color::orange()};
NewButton button_rename_timestamp{
{4 * 8, 34 * 8, 4 * 8, 32},
{4 * 8, 29 * 8, 4 * 8, 32},
{},
&bitmap_icon_options_datetime,
Color::orange(),
/*vcenter*/ true};
NewButton button_open_iq_trim{
{9 * 8, 34 * 8, 4 * 8, 32},
{4 * 8, 34 * 8, 4 * 8, 32},
{},
&bitmap_icon_trim,
Color::orange()};
NewButton button_show_hidden_files{
{13 * 8, 34 * 8, 4 * 8, 32},
{17 * 8, 34 * 8, 4 * 8, 32},
{},
&bitmap_icon_hide,
Color::dark_grey()};
+22 -23
View File
@@ -26,7 +26,7 @@
namespace ui {
static const char16_t* firmware_folder = u"/FIRMWARE";
static const std::filesystem::path firmware_path = u"/FIRMWARE";
// Firmware image validation
static const char* hackrf_magic = "HACKRFFW";
@@ -84,30 +84,29 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav)
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
ensure_directory(firmware_folder);
ensure_directory(firmware_path);
for (const auto& entry : std::filesystem::directory_iterator(firmware_folder, u"*.bin")) {
auto filename = entry.path().filename();
auto path = entry.path().native();
auto add_firmware_items = [&](
const std::filesystem::path& folder_path,
const std::filesystem::path& wild,
ui::Color color) {
for (const auto& entry : std::filesystem::directory_iterator(folder_path, wild)) {
auto filename = entry.path().filename();
auto path = entry.path().native();
menu_view.add_item({filename.string().substr(0, max_filename_length),
ui::Color::red(),
&bitmap_icon_temperature,
[this, path](KeyEvent) {
this->firmware_selected(path);
}});
}
for (const auto& entry : std::filesystem::directory_iterator(firmware_folder, u"*.tar")) {
auto filename = entry.path().filename();
auto path = entry.path().native();
menu_view.add_item({filename.string().substr(0, max_filename_length),
color,
&bitmap_icon_temperature,
[this, path](KeyEvent) {
this->firmware_selected(path);
}});
}
};
menu_view.add_item({filename.string().substr(0, max_filename_length),
ui::Color::purple(),
&bitmap_icon_temperature,
[this, path](KeyEvent) {
this->firmware_selected(path);
}});
}
add_firmware_items(firmware_path, u"*.bin", ui::Color::red());
add_firmware_items(firmware_path, u"*.tar", ui::Color::purple());
// add_firmware_items(user_firmware_folder,u"*.bin", ui::Color::purple());
}
void FlashUtilityView::firmware_selected(std::filesystem::path::string_type path) {
@@ -179,4 +178,4 @@ void FlashUtilityView::focus() {
menu_view.focus();
}
} /* namespace ui */
} /* namespace ui */
+1 -1
View File
@@ -228,7 +228,7 @@ void FrequencyManagerView::on_edit_freq() {
void FrequencyManagerView::on_edit_desc() {
temp_buffer_ = current_entry().description;
text_prompt(nav_, temp_buffer_, desc_edit_max, [this](std::string& new_desc) {
text_prompt(nav_, temp_buffer_, freqman_max_desc_size, [this](std::string& new_desc) {
auto entry = current_entry();
entry.description = std::move(new_desc);
db_.replace_entry(current_index(), entry);
+3 -5
View File
@@ -40,8 +40,6 @@ class FreqManBaseView : public View {
void focus() override;
static constexpr size_t desc_edit_max = 0x80;
protected:
using options_t = OptionsField::options_t;
@@ -63,11 +61,11 @@ class FreqManBaseView : public View {
/* The top section (category) is 20px tall. */
Labels label_category{
{{0, 2}, "Category:", Color::light_grey()}};
{{0, 2}, "F:", Color::light_grey()}};
OptionsField options_category{
{9 * 8, 2},
14 /* length */,
{3 * 8, 2},
20 /* length */,
{}};
FreqManUIList freqlist_view{
+37 -5
View File
@@ -27,6 +27,7 @@
#include "baseband_api.hpp"
#include "file.hpp"
#include "oversample.hpp"
#include "ui_font_fixed_8x16.hpp"
using namespace portapack;
using namespace tonekey;
@@ -39,6 +40,8 @@ void LevelView::focus() {
}
LevelView::~LevelView() {
// reset performance counters request to default
shared_memory.request_m4_performance_counter = 0;
receiver_model.disable();
baseband::shutdown();
}
@@ -58,12 +61,16 @@ LevelView::LevelView(NavigationView& nav)
&text_ctcss,
&freq_stats_rssi,
&freq_stats_db,
&freq_stats_rx,
&audio_mode,
&peak_mode,
&rssi,
&rssi_graph});
// activate vertical bar mode
rssi.set_vertical_rssi(true);
// activate counters for RxSat
shared_memory.request_m4_performance_counter = 2;
change_mode(NFM_MODULATION); // Start on AM
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector
@@ -139,13 +146,15 @@ LevelView::LevelView(NavigationView& nav)
freqman_set_step_option_short(step_mode);
freq_stats_rssi.set_style(&Styles::white);
freq_stats_db.set_style(&Styles::white);
freq_stats_rx.set_style(&Styles::white);
}
void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
static int16_t last_max_db = -1000;
static int16_t last_min_rssi = -1000;
static int16_t last_avg_rssi = -1000;
static int16_t last_max_rssi = -1000;
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;
static uint8_t last_rx_sat = 0;
rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db);
@@ -159,8 +168,31 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
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_int(last_min_rssi) + "/" + to_string_dec_int(last_avg_rssi) + "/" + to_string_dec_int(last_max_rssi) + ",dt: " + to_string_dec_int(rssi_graph.get_graph_delta()));
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) + ", dt: " + to_string_dec_uint(rssi_graph.get_graph_delta()));
}
// refresh sat
uint8_t rx_sat = ((uint32_t)shared_memory.m4_performance_counter) * 100 / 127;
if (last_rx_sat != rx_sat) {
last_rx_sat = rx_sat;
freq_stats_rx.set("RxSat: " + to_string_dec_uint(rx_sat) + "%");
uint8_t br = 0;
uint8_t bg = 0;
uint8_t bb = 0;
if (rx_sat <= 80) {
bg = (255 * rx_sat) / 80;
bb = 255 - bg;
} else if (rx_sat > 80) {
br = (255 * (rx_sat - 80)) / 20;
bg = 255 - br;
}
Style style_freq_stats_rx{
.font = font::fixed_8x16,
.background = {br, bg, bb},
.foreground = {255, 255, 255},
};
freq_stats_rx.set_style(&style_freq_stats_rx);
}
} /* on_statistic_updates */
size_t LevelView::change_mode(freqman_index_t new_mod) {
+10 -6
View File
@@ -62,8 +62,6 @@ class LevelView : public View {
void on_statistics_update(const ChannelStatistics& statistics);
void set_display_freq(int64_t freq);
// TODO: needed?
int32_t db{0};
rf::Frequency freq_ = {0};
Labels labels{
@@ -118,12 +116,12 @@ class LevelView : public View {
// RSSI: XX/XX/XXX,dt: XX
Text freq_stats_rssi{
{0 * 8, 3 * 16 + 4, 22 * 8, 14},
{0 * 8, 3 * 16 + 4, 22 * 8, 1 * 16},
};
// Power: -XXX db
Text freq_stats_db{
{0 * 8, 4 * 16 + 4, 14 * 8, 14},
{0 * 8, 4 * 16 + 4, 15 * 8, 1 * 16},
};
OptionsField peak_mode{
@@ -138,6 +136,7 @@ class LevelView : public View {
{"peak:5s", 5000},
{"peak:10s", 10000},
}};
OptionsField rssi_resolution{
{44 + 20 * 8, 4 * 16 + 4},
4,
@@ -149,14 +148,19 @@ class LevelView : public View {
{"240x", 240},
}};
// RxSat: XX%
Text freq_stats_rx{
{0 * 8, 5 * 16 + 4, 10 * 8, 1 * 16},
};
RSSIGraph rssi_graph{
// 240x320 =>
{0, 5 * 16 + 4, 240 - 5 * 8, 320 - (5 * 16 + 4)},
{0, 6 * 16 + 4, 240 - 5 * 8, 320 - (6 * 16 + 4)},
};
RSSI rssi{
// 240x320 =>
{240 - 5 * 8, 5 * 16 + 4, 5 * 8, 320 - (5 * 16 + 4)},
{240 - 5 * 8, 6 * 16 + 4, 5 * 8, 320 - (6 * 16 + 4)},
};
void handle_coded_squelch(const uint32_t value);
@@ -338,6 +338,7 @@ GlassView::GlassView(
&field_trigger,
&button_jump,
&button_rst,
&field_rx_iq_phase_cal,
&freq_stats});
load_presets(); // Load available presets from TXT files (or default).
@@ -474,6 +475,13 @@ GlassView::GlassView(
reset_live_view();
};
field_rx_iq_phase_cal.set_range(0, hackrf_r9 ? 63 : 31); // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31]
field_rx_iq_phase_cal.set_value(get_spec_iq_phase_calibration_value()); // using accessor function of AnalogAudioView to read iq_phase_calibration_value from rx_audio.ini
field_rx_iq_phase_cal.on_change = [this](int32_t v) {
set_spec_iq_phase_calibration_value(v); // using accessor function of AnalogAudioView to write inside SPEC submenu, register value to max283x and save it to rx_audio.ini
};
set_spec_iq_phase_calibration_value(get_spec_iq_phase_calibration_value()); // initialize iq_phase_calibration in radio
display.scroll_set_area(109, 319);
// trigger:
@@ -491,6 +499,15 @@ GlassView::GlassView(
receiver_model.enable();
}
uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value
return iq_phase_calibration_value;
}
void GlassView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // define accessor functions
iq_phase_calibration_value = cal_value;
radio::set_rx_max283x_iq_phase_calibration(iq_phase_calibration_value);
}
void GlassView::load_presets() {
File presets_file;
auto error = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
@@ -69,6 +69,9 @@ class GlassView : public View {
void on_hide() override;
void focus() override;
uint8_t get_spec_iq_phase_calibration_value();
void set_spec_iq_phase_calibration_value(uint8_t cal_value);
private:
NavigationView& nav_;
RxRadioState radio_state_{ReceiverModel::Mode::SpectrumAnalysis};
@@ -79,8 +82,9 @@ class GlassView : public View {
uint8_t filter_index = 0; // OFF
uint8_t trigger = 32;
uint8_t mode = LOOKING_GLASS_FASTSCAN;
uint8_t live_frequency_view = 0; // Spectrum
uint8_t live_frequency_integrate = 3; // Default (3 * old value + new_value) / 4
uint8_t live_frequency_view = 0; // Spectrum
uint8_t live_frequency_integrate = 3; // Default (3 * old value + new_value) / 4
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
app_settings::SettingsManager settings_{
"rx_glass"sv,
app_settings::Mode::RX,
@@ -93,6 +97,7 @@ class GlassView : public View {
{"scan_mode"sv, &mode},
{"freq_view"sv, &live_frequency_view},
{"freq_integrate"sv, &live_frequency_integrate},
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
}};
struct preset_entry {
@@ -160,7 +165,7 @@ class GlassView : public View {
{{0, 0 * 16}, "MIN: MAX: LNA VGA ", Color::light_grey()},
{{0, 1 * 16}, "RANGE: FILTER: AMP:", Color::light_grey()},
{{0, 2 * 16}, "PRESET:", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz", Color::light_grey()},
{{0, 3 * 16}, "MARKER: MHz RXIQCAL", Color::light_grey()},
{{0, 4 * 16}, "RES: STEP:", Color::light_grey()}};
NumberField field_frequency_min{
@@ -208,6 +213,14 @@ class GlassView : public View {
{7 * 8, 3 * 16, 9 * 8, 16},
""};
NumberField field_rx_iq_phase_cal{
{28 * 8, 3 * 16},
2,
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
1,
' ',
};
NumberField field_trigger{
{4 * 8, 4 * 16},
3,
+7 -14
View File
@@ -338,7 +338,7 @@ MicTXView::MicTXView(
&field_rxlna,
&field_rxvga,
&field_rxamp,
hackrf_r9 ? &field_tx_iq_phase_cal_2839 : &field_tx_iq_phase_cal_2837,
&field_tx_iq_phase_cal,
&tx_button,
&tx_icon});
@@ -372,19 +372,12 @@ MicTXView::MicTXView(
};
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
if (hackrf_r9) { // MAX2839 has 6 bits IQ CAL phasse adjustment.
field_tx_iq_phase_cal_2839.set_value(iq_phase_calibration_value);
field_tx_iq_phase_cal_2839.on_change = [this](int32_t v) {
iq_phase_calibration_value = v;
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
};
} else { // MAX2837 has 5 bits IQ CAL phase adjustment.
field_tx_iq_phase_cal_2837.set_value(iq_phase_calibration_value);
field_tx_iq_phase_cal_2837.on_change = [this](int32_t v) {
iq_phase_calibration_value = v;
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
};
}
field_tx_iq_phase_cal.set_range(0, hackrf_r9 ? 63 : 31); // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31]
field_tx_iq_phase_cal.set_value(iq_phase_calibration_value);
field_tx_iq_phase_cal.on_change = [this](int32_t v) {
iq_phase_calibration_value = v;
radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value);
};
options_gain.on_change = [this](size_t, int32_t v) {
mic_gain_x10 = v;
+2 -10
View File
@@ -342,18 +342,10 @@ class MicTXView : public View {
' ',
};
NumberField field_tx_iq_phase_cal_2837{
NumberField field_tx_iq_phase_cal{
{24 * 8, (33 * 8)},
2,
{0, 31}, // 5 bits IQ CAL phase adjustment.
1,
' ',
};
NumberField field_tx_iq_phase_cal_2839{
{24 * 8, (33 * 8)},
2,
{0, 63}, // 6 bits IQ CAL phasse adjustment.
{0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later)
1,
' ',
};
+37 -22
View File
@@ -49,7 +49,13 @@ namespace fs = std::filesystem;
namespace ui {
void ReconView::reload_restart_recon() {
// force reload of current
change_mode(field_mode.selected_index_value());
uint8_t previous_index = current_index;
reset_indexes();
frequency_file_load();
current_index = previous_index;
handle_retune();
if (frequency_list.size() > 0) {
if (fwd) {
button_dir.set_text("FW>");
@@ -104,18 +110,19 @@ void ReconView::set_loop_config(bool v) {
void ReconView::recon_stop_recording(bool exiting) {
if (is_recording) {
if (field_mode.selected_index_value() == SPEC_MODULATION)
button_audio_app.set_text("RAW");
else
button_audio_app.set_text("AUDIO");
button_audio_app.set_style(&Styles::white);
record_view->stop();
button_config.set_style(&Styles::white);
is_recording = false;
// repeater mode
if (!exiting && persistent_memory::recon_repeat_recorded()) {
start_repeat();
if (field_mode.selected_index_value() == SPEC_MODULATION) {
button_audio_app.set_text("RAW");
// repeater mode
if (!exiting && persistent_memory::recon_repeat_recorded()) {
start_repeat();
}
} else {
button_audio_app.set_text("AUDIO");
}
button_audio_app.set_style(&Styles::white);
button_config.set_style(&Styles::white);
}
}
@@ -1148,7 +1155,7 @@ void ReconView::on_stepper_delta(int32_t v) {
}
size_t ReconView::change_mode(freqman_index_t new_mod) {
if (recon_tx || is_repeat_active())
if (recon_tx || is_repeat_active() || is_recording)
return 0;
field_mode.on_change = [this](size_t, OptionsField::value_t) {};
field_bw.on_change = [this](size_t, OptionsField::value_t) {};
@@ -1157,16 +1164,21 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
remove_child(record_view.get());
record_view.reset();
}
if (persistent_memory::recon_repeat_recorded()) {
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"RECON_REPEAT.C16", u"CAPTURES",
RecordView::FileType::RawS16, 16384, 3);
record_view->set_filename_as_is(true);
} else if (new_mod == SPEC_MODULATION) {
if (field_mode.selected_index_value() != SPEC_MODULATION) {
audio::output::stop();
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"AUTO_RAW", u"CAPTURES",
RecordView::FileType::RawS16, 16384, 3);
}
if (new_mod == SPEC_MODULATION) {
if (persistent_memory::recon_repeat_recorded()) {
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
u"RECON_REPEAT.C16", u"CAPTURES",
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},
u"AUTO_RAW", u"CAPTURES",
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},
u"AUTO_AUDIO", u"AUDIO",
@@ -1314,9 +1326,6 @@ bool ReconView::is_repeat_active() const {
void ReconView::start_repeat() {
// Prepare to send a file.
std::filesystem::path rawfile = u"/" + repeat_rec_path + u"/" + repeat_rec_file;
std::filesystem::path rawmeta = u"/" + repeat_rec_path + u"/" + repeat_rec_meta;
if (recon_tx == false) {
recon_tx = true;
@@ -1434,6 +1443,12 @@ void ReconView::stop_repeat(const bool do_loop) {
} else {
repeat_cur_rep = 0;
recon_tx = false;
if (persistent_memory::recon_repeat_recorded_file_mode() == RECON_REPEAT_AND_KEEP) {
// rename file here to keep
std::filesystem::path base_path = next_filename_matching_pattern(repeat_rec_path / u"REC_????.*");
rename_file(rawfile, base_path.replace_extension(u".C16"));
rename_file(rawmeta, base_path.replace_extension(u".TXT"));
}
reload_restart_recon();
progressbar.hidden(true);
set_dirty(); // fix progressbar no hiding
+3
View File
@@ -198,6 +198,9 @@ class ReconView : public View {
bool repeat_ready_signal{false};
bool recon_tx{false};
std::filesystem::path rawfile = u"/" + repeat_rec_path + u"/" + repeat_rec_file;
std::filesystem::path rawmeta = u"/" + repeat_rec_path + u"/" + repeat_rec_meta;
// Persisted settings.
SettingsStore ui_settings{
"recon"sv,
@@ -103,6 +103,7 @@ void ReconSetupViewMore::save() {
persistent_memory::set_recon_update_ranges_when_recon(checkbox_update_ranges_when_recon.value());
persistent_memory::set_recon_auto_record_locked(checkbox_auto_record_locked.value());
persistent_memory::set_recon_repeat_recorded(checkbox_repeat_recorded.value());
persistent_memory::set_recon_repeat_recorded_file_mode(field_repeat_file_mode.selected_index_value());
persistent_memory::set_recon_repeat_nb(field_repeat_nb.value());
persistent_memory::set_recon_repeat_amp(checkbox_repeat_amp.value());
persistent_memory::set_recon_repeat_gain(field_repeat_gain.value());
@@ -125,6 +126,7 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
&checkbox_update_ranges_when_recon,
&checkbox_auto_record_locked,
&checkbox_repeat_recorded,
&field_repeat_file_mode,
&text_repeat_nb,
&field_repeat_nb,
&checkbox_repeat_amp,
@@ -135,6 +137,7 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
// tx options have to be in yellow to inform the users that activating them will make the device transmit
checkbox_repeat_recorded.set_style(&Styles::yellow);
field_repeat_file_mode.set_style(&Styles::yellow);
text_repeat_nb.set_style(&Styles::yellow);
field_repeat_nb.set_style(&Styles::yellow);
checkbox_repeat_amp.set_style(&Styles::yellow);
@@ -150,6 +153,7 @@ ReconSetupViewMore::ReconSetupViewMore(NavigationView& nav, Rect parent_rect)
checkbox_update_ranges_when_recon.set_value(persistent_memory::recon_update_ranges_when_recon());
checkbox_auto_record_locked.set_value(persistent_memory::recon_auto_record_locked());
checkbox_repeat_recorded.set_value(persistent_memory::recon_repeat_recorded());
field_repeat_file_mode.set_selected_index(persistent_memory::recon_repeat_recorded_file_mode());
checkbox_repeat_amp.set_value(persistent_memory::recon_repeat_amp());
field_repeat_nb.set_value(persistent_memory::recon_repeat_nb());
field_repeat_gain.set_value(persistent_memory::recon_repeat_gain());
@@ -38,16 +38,19 @@
#endif
#define OneMHz 1000000
// modes
// main app mode
#define RECON_MATCH_CONTINUOUS 0
#define RECON_MATCH_SPARSE 1
// repeater mode
#define RECON_REPEAT_AND_DELETE 0
#define RECON_REPEAT_AND_KEEP 1
// statistics update interval in ms (change here if the statistics API is changing it's pace)
#define STATS_UPDATE_INTERVAL 100
// maximum lock duration
#define RECON_MAX_LOCK_DURATION 9900
#define RECON_DEF_SQUELCH -14
// default number of match to have a lock
@@ -150,15 +153,21 @@ class ReconSetupViewMore : public View {
Checkbox checkbox_repeat_recorded{
{1 * 8, 162},
3,
"repeater,"};
0,
""};
OptionsField field_repeat_file_mode{
{4 * 8 + 3, 165},
13,
{{"repeat,delete", RECON_REPEAT_AND_DELETE},
{"repeat,keep ", RECON_REPEAT_AND_KEEP}}};
Text text_repeat_nb{
{14 * 8, 165, 3 * 8, 22},
{20 * 8, 165, 3 * 8, 22},
"nb:"};
NumberField field_repeat_nb{
{17 * 8, 165},
{23 * 8, 165},
2,
{1, 99},
1,
+26 -21
View File
@@ -4,6 +4,7 @@
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyright (C) 2024 u-foka
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
@@ -835,28 +836,32 @@ void SetMenuColorView::focus() {
/* SettingsMenuView **************************************/
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
if (pmem::show_gui_return_icon()) {
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
}
add_items({
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<AppSettingsView>(); }},
{"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav]() { nav.push<SetAudioView>(); }},
{"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push<TouchCalibrationView>(); }},
{"Config Mode", ui::Color::dark_cyan(), &bitmap_icon_clk_ext, [&nav]() { nav.push<SetConfigModeView>(); }},
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetConverterSettingsView>(); }},
{"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav]() { nav.push<SetDateTimeView>(); }},
{"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<SetEncoderDialView>(); }},
{"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetFrequencyCorrectionView>(); }},
{"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<SetPersistentMemoryView>(); }},
{"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetRadioView>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SetSDCardView>(); }},
{"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav]() { nav.push<SetUIView>(); }},
{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push<SetQRCodeView>(); }},
{"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push<SetFakeBrightnessView>(); }},
{"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push<SetMenuColorView>(); }},
});
SettingsMenuView::SettingsMenuView(NavigationView& nav)
: nav_(nav) {
set_max_rows(2); // allow wider buttons
}
void SettingsMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_items({
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_notepad, [this]() { nav_.push<AppSettingsView>(); }},
{"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [this]() { nav_.push<SetAudioView>(); }},
{"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [this]() { nav_.push<TouchCalibrationView>(); }},
{"Config Mode", ui::Color::dark_cyan(), &bitmap_icon_clk_ext, [this]() { nav_.push<SetConfigModeView>(); }},
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push<SetConverterSettingsView>(); }},
{"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [this]() { nav_.push<SetDateTimeView>(); }},
{"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push<SetEncoderDialView>(); }},
{"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push<SetFrequencyCorrectionView>(); }},
{"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push<SetPersistentMemoryView>(); }},
{"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push<SetRadioView>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push<SetSDCardView>(); }},
{"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push<SetUIView>(); }},
{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push<SetQRCodeView>(); }},
{"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetFakeBrightnessView>(); }},
{"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push<SetMenuColorView>(); }},
});
}
} /* namespace ui */
+5 -1
View File
@@ -4,6 +4,7 @@
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyright (C) 2024 u-foka
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
@@ -792,8 +793,11 @@ class SetMenuColorView : public View {
class SettingsMenuView : public BtnGridView {
public:
SettingsMenuView(NavigationView& nav);
std::string title() const override { return "Settings"; };
private:
NavigationView& nav_;
void on_populate() override;
};
} /* namespace ui */
+42 -4
View File
@@ -5764,8 +5764,8 @@ static constexpr uint8_t bitmap_icon_brightness_data[] = {
0x00,
0x80,
0x01,
0x80,
0x01,
0x84,
0x21,
0x08,
0x10,
0xC0,
@@ -5786,8 +5786,8 @@ static constexpr uint8_t bitmap_icon_brightness_data[] = {
0x03,
0x08,
0x10,
0x80,
0x01,
0x84,
0x21,
0x80,
0x01,
0x00,
@@ -5797,6 +5797,44 @@ static constexpr Bitmap bitmap_icon_brightness{
{16, 16},
bitmap_icon_brightness_data};
static constexpr uint8_t bitmap_icon_clean_data[] = {
0x00,
0x00,
0xC0,
0x01,
0x20,
0x02,
0xFC,
0x1F,
0x00,
0x00,
0x08,
0x08,
0xE8,
0x08,
0xA8,
0x09,
0xA8,
0x0B,
0x28,
0x0A,
0x28,
0x0A,
0x28,
0x0A,
0xE8,
0x0B,
0x08,
0x08,
0xF0,
0x07,
0x00,
0x00,
};
static constexpr Bitmap bitmap_icon_clean{
{16, 16},
bitmap_icon_clean_data};
} /* namespace ui */
#endif /*__BITMAP_HPP__*/
+79 -20
View File
@@ -20,7 +20,7 @@
* Boston, MA 02110-1301, USA.
*/
// Code from https://github.com/Flipper-XFW/Xtreme-Apps/tree/04c3a60093e2c2378e79498b4505aa8072980a42/ble_spam/protocols
// Code from https://github.com/Next-Flip/Momentum-Apps/blob/dev/ble_spam/
// Thanks for the work of the original creators!
#include "ui_blespam.hpp"
@@ -109,7 +109,8 @@ BLESpamView::BLESpamView(NavigationView& nav)
console.writeln("Based on work of:");
console.writeln("@Willy-JL, @ECTO-1A,");
console.writeln("@Spooks4576, @iNetro");
console.writeln("");
console.writeln("---");
console.writeln("iOS crash + Android\nattacks are patched\non new devices.");
#endif
changePacket(true); // init
}
@@ -293,6 +294,39 @@ void BLESpamView::createWindowsPacket() {
std::copy(res.begin(), res.end(), advertisementData);
}
void BLESpamView::createNameSpamPacket() {
const char* names[] = {"PortaHack", "PwnBt", "iSpam", "GenericFoodVagon", "SignalSnoop", "ByteBandit", "RadioRogue", "RadioRebel", "ByteBlast"};
const char* name = names[rand() % 9]; //"PortaHack";
uint8_t name_len = strlen(name);
uint8_t size = 12 + name_len;
uint8_t i = 0;
packet[i++] = 2; // Size
packet[i++] = 0x01; // AD Type (Flags)
packet[i++] = 0x06; // Flags
packet[i++] = name_len + 1; // Size
packet[i++] = 0x09; // AD Type (Complete Local Name)
memcpy(&packet[i], name, name_len); // Device Name
i += name_len;
packet[i++] = 3; // Size
packet[i++] = 0x02; // AD Type (Incomplete Service UUID List)
packet[i++] = 0x12; // Service UUID (Human Interface Device)
packet[i++] = 0x18; // ...
packet[i++] = 2; // Size
packet[i++] = 0x0A; // AD Type (Tx Power Level)
packet[i++] = 0x00; // 0dBm
// size, packet
std::string res = to_string_hex_array(packet, size);
memset(advertisementData, 0, sizeof(advertisementData));
std::copy(res.begin(), res.end(), advertisementData);
}
void BLESpamView::createIosPacket(bool crash = false) {
uint8_t ios_packet_sizes[18] = {0, 0, 0, 0, 0, 24, 0, 31, 0, 12, 0, 0, 20, 0, 12, 11, 11, 17};
ContinuityType type;
@@ -509,6 +543,48 @@ void BLESpamView::createFastPairPacket() {
std::copy(res.begin(), res.end(), advertisementData);
}
void BLESpamView::createAnyPacket(bool safe) {
ATK_TYPE type[] = {
ATK_ANDROID,
ATK_IOS,
ATK_WINDOWS,
ATK_SAMSUNG,
ATK_NAMESPAM,
ATK_IOS_CRASH};
ATK_TYPE attackType = type[rand() % (COUNT_OF(type) - (1 ? safe : 0))];
createPacket(attackType);
}
void BLESpamView::createPacket(ATK_TYPE attackType) {
switch (attackType) {
case ATK_IOS_CRASH:
createIosPacket(true);
break;
case ATK_IOS:
createIosPacket(false);
break;
case ATK_SAMSUNG:
createSamsungPacket();
break;
case ATK_WINDOWS:
createWindowsPacket();
break;
case ATK_NAMESPAM:
createNameSpamPacket();
break;
case ATK_ALL_SAFE:
createAnyPacket(true);
break;
case ATK_ALL:
createAnyPacket(false);
break;
default:
case ATK_ANDROID:
createFastPairPacket();
break;
}
}
void BLESpamView::changePacket(bool forced = false) {
counter++; // need to send it multiple times to be accepted
if (counter >= 4 || forced) {
@@ -517,24 +593,7 @@ void BLESpamView::changePacket(bool forced = false) {
randomizeMac();
randomChn();
if (randomDev || forced) {
switch (attackType) {
case ATK_IOS_CRASH:
createIosPacket(true);
break;
case ATK_IOS:
createIosPacket(false);
break;
case ATK_SAMSUNG:
createSamsungPacket();
break;
case ATK_WINDOWS:
createWindowsPacket();
break;
default:
case ATK_ANDROID:
createFastPairPacket();
break;
}
createPacket(attackType);
}
// rate limit console display
#ifdef BLESPMUSECONSOLE
+11 -2
View File
@@ -49,7 +49,10 @@ enum ATK_TYPE {
ATK_IOS,
ATK_IOS_CRASH,
ATK_WINDOWS,
ATK_SAMSUNG
ATK_SAMSUNG,
ATK_NAMESPAM,
ATK_ALL_SAFE,
ATK_ALL
};
enum PKT_TYPE {
PKT_TYPE_INVALID_TYPE,
@@ -124,7 +127,10 @@ class BLESpamView : public View {
{"iOs", 1},
{"iOs crash", 2},
{"Windows", 3},
{"Samsung", 4}}};
{"Samsung", 4},
{"NameSpam", 5},
{"All-Safe", 6},
{"All", 7}}};
bool is_running{false};
@@ -148,6 +154,9 @@ class BLESpamView : public View {
void createIosPacket(bool crash);
void createSamsungPacket();
void createWindowsPacket();
void createNameSpamPacket();
void createAnyPacket(bool safe);
void createPacket(ATK_TYPE attackType);
void changePacket(bool forced);
void on_tx_progress(const bool done);
+1 -1
View File
@@ -1867,7 +1867,7 @@ static byte menuselect(byte lines) { // Selection (1 line = 16 items)
// *** S T A C K
static void floatstack() {
memcpy(ds, &ds[1], (DATASTACKSIZE - 1) * sizeof(double));
memmove(ds, &ds[1], (DATASTACKSIZE - 1) * sizeof(double));
dp--;
}
+2 -2
View File
@@ -76,7 +76,7 @@ __attribute__((section(".external_app.app_calculator.application_information"),
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'}, // optional
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+6
View File
@@ -62,6 +62,11 @@ set(EXTCPPSRC
external/keyfob/main.cpp
external/keyfob/ui_keyfob.cpp
external/keyfob/ui_keyfob.hpp
#extsensors
external/extsensors/main.cpp
external/extsensors/ui_extsensors.cpp
external/extsensors/ui_extsensors.hpp
)
set(EXTAPPLIST
@@ -80,4 +85,5 @@ set(EXTAPPLIST
spainter
keyfob
tetris
extsensors
)
+9
View File
@@ -38,6 +38,7 @@ MEMORY
ram_external_app_spainter(rwx) : org = 0xADBC0000, len = 32k
ram_external_app_keyfob(rwx) : org = 0xADBD0000, len = 32k
ram_external_app_tetris(rwx) : org = 0xADBE0000, len = 32k
ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k
}
SECTIONS
@@ -132,4 +133,12 @@ SECTIONS
*(*ui*external_app*tetris*);
} > ram_external_app_tetris
.external_app_extsensors : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_extsensors.application_information));
*(*ui*external_app*extsensors*);
} > ram_external_app_extsensors
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_extsensors.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::extsensors {
void initialize_app(ui::NavigationView& nav) {
nav.push<ExtSensorsView>();
}
} // namespace ui::external_app::extsensors
extern "C" {
__attribute__((section(".external_app.app_extsensors.application_information"), used)) application_information_t _application_information_extsensors = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::extsensors::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "ExtSensor",
/*.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::DEBUG,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,86 @@
/*
* 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_extsensors.hpp"
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
using namespace ui;
namespace ui::external_app::extsensors {
void ExtSensorsView::focus() {
text_info.focus();
}
ExtSensorsView::ExtSensorsView(NavigationView& nav)
: nav_{nav} {
add_children({&labels,
&text_info,
&text_gps,
&text_orientation,
&text_envl1,
&text_envl2});
}
ExtSensorsView::~ExtSensorsView() {
}
void ExtSensorsView::on_any() {
if (has_data == false) {
// update text
text_info.set("Found ext module."); // todo do an ext module check for type
}
has_data = true;
}
void ExtSensorsView::on_gps(const GPSPosDataMessage* msg) {
on_any();
std::string tmp = to_string_decimal(msg->lat, 5);
tmp += "; ";
tmp += to_string_decimal(msg->lon, 5);
text_gps.set(tmp);
}
void ExtSensorsView::on_orientation(const OrientationDataMessage* msg) {
on_any();
std::string tmp = to_string_dec_uint(msg->angle);
tmp += (char)176; // °
if (msg->tilt < 400) {
tmp += "; T: " + to_string_dec_int(msg->tilt);
}
text_orientation.set(tmp);
}
void ExtSensorsView::on_environment(const EnvironmentDataMessage* msg) {
on_any();
std::string tmp = "T: " + to_string_decimal(msg->temperature, 2); // temperature
tmp += (char)176; // °
tmp += "C";
tmp += "; H: " + to_string_decimal(msg->humidity, 1) + "%"; // humidity
text_envl1.set(tmp);
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa; L:"; // pressure
tmp += to_string_dec_int(msg->light) + " LUX"; // light
text_envl2.set(tmp);
}
} // namespace ui::external_app::extsensors
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
// Code from https://github.com/Flipper-XFW/Xtreme-Apps/tree/04c3a60093e2c2378e79498b4505aa8072980a42/ble_spam/protocols
// Thanks for the work of the original creators!
// Saying thanks in the main view!
#ifndef __UI_EXTSENSORS_H__
#define __UI_EXTSENSORS_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_record_view.hpp"
#include "app_settings.hpp"
#include "utility.hpp"
using namespace ui;
namespace ui::external_app::extsensors {
class ExtSensorsView : public View {
public:
ExtSensorsView(NavigationView& nav);
~ExtSensorsView();
void focus() override;
std::string title() const override {
return "ExtSensor";
};
private:
NavigationView& nav_;
bool has_data = false;
Labels labels{
{{0 * 8, 3 * 16}, "GPS:", Color::light_grey()},
{{0 * 8, 5 * 16}, "ORI:", Color::light_grey()},
{{0 * 8, 7 * 16}, "ENV:", Color::light_grey()}};
Text text_info{{0 * 8, 0 * 8, 30 * 8, 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}, "-"};
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
void on_any();
void on_gps(const GPSPosDataMessage* msg);
void on_orientation(const OrientationDataMessage* msg);
void on_environment(const EnvironmentDataMessage* msg);
MessageHandlerRegistration message_handler_gps{
Message::ID::GPSPosData,
[this](Message* const p) {
const auto message = static_cast<const GPSPosDataMessage*>(p);
this->on_gps(message);
}};
MessageHandlerRegistration message_handler_orientation{
Message::ID::OrientationData,
[this](Message* const p) {
const auto message = static_cast<const OrientationDataMessage*>(p);
this->on_orientation(message);
}};
MessageHandlerRegistration message_handler_environment{
Message::ID::EnvironmentData,
[this](Message* const p) {
const auto message = static_cast<const EnvironmentDataMessage*>(p);
this->on_environment(message);
}};
};
}; // namespace ui::external_app::extsensors
#endif /*__UI_EXTSENSORS_H__*/
+1 -1
View File
@@ -76,7 +76,7 @@ __attribute__((section(".external_app.app_font_viewer.application_information"),
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'},
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+2 -2
View File
@@ -76,7 +76,7 @@ __attribute__((section(".external_app.app_pacman.application_information"), used
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'}, // optional
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+62 -17
View File
@@ -43,6 +43,16 @@ boolean but_DOWN = false; // 50
boolean but_LEFT = false; // 48
boolean but_RIGHT = false; // 46
enum cheat_code_keymap {
UP,
DOWN,
LEFT,
RIGHT
};
enum cheat_code_keymap cheat_code[] = {UP, DOWN, UP, DOWN, RIGHT, LEFT, RIGHT, LEFT};
byte cheat_code_index = 0;
/******************************************************************************/
/* GAME VARIABLES AND DEFINITIONS */
/******************************************************************************/
@@ -1280,29 +1290,64 @@ class Playfield {
but_A = false;
GAMEPAUSED = 1;
} else if (but_LEFT && DEMO == 1 && GAMEPAUSED == 0) { // -level
cheat_level = true;
if ((cheat_code[cheat_code_index] == 2) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_level = true;
if (LEVEL > 1) {
LEVEL--;
}
Init();
}
but_LEFT = false;
if (LEVEL > 1) {
LEVEL--;
}
Init();
} else if (but_RIGHT && DEMO == 1 && GAMEPAUSED == 0) { // +level
cheat_level = true;
but_RIGHT = false;
if (LEVEL < 255) {
LEVEL++;
if ((cheat_code[cheat_code_index] == 3) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
Init();
if (cheat_code_index == 8) {
cheat_level = true;
if (LEVEL < 255) {
LEVEL++;
}
Init();
}
but_RIGHT = false;
} else if (but_UP && DEMO == 1 && GAMEPAUSED == 0) { // full of lifes
cheat_lifes = true;
if ((cheat_code[cheat_code_index] == 0) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_lifes = true;
Init();
}
but_UP = false;
Init();
} else if (but_DOWN && DEMO == 1 && GAMEPAUSED == 0) { // reset
cheat_level = false;
cheat_lifes = false;
but_DOWN = false;
LIFES = START_LIFES;
Init();
if ((cheat_code[cheat_code_index] == 1) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_level = false;
cheat_lifes = false;
but_DOWN = false;
LIFES = START_LIFES;
cheat_code_index = 0;
Init();
}
}
if (GAMEPAUSED && but_A && DEMO == 0) {
+2 -2
View File
@@ -76,7 +76,7 @@ __attribute__((section(".external_app.app_tetris.application_information"), used
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.m4_app_tag = portapack::spi_flash::image_tag_noop */ {'\0', '\0', '\0', '\0'}, // optional
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+9
View File
@@ -461,6 +461,15 @@ std::string path::string() const {
return conv.to_bytes(native());
}
// appends a string to the end of filename, but leaves the extension asd.txt + "fg" -> asdfg.txt
path& path::append_filename(const string_type& str) {
const auto t = extension().native();
_s.erase(_s.size() - t.size()); // remove extension
_s += str; // append string
_s += t; // add back extension
return *this;
}
path& path::replace_extension(const path& replacement) {
const auto t = extension().native();
_s.erase(_s.size() - t.size());
+2
View File
@@ -155,6 +155,8 @@ struct path {
path& replace_extension(const path& replacement = path());
path& append_filename(const string_type& str);
private:
string_type _s;
};
+2 -2
View File
@@ -376,7 +376,7 @@ bool parse_freqman_entry(std::string_view str, freqman_entry& entry) {
} else if (key == "c") {
entry.tone = parse_tone_key(value);
} else if (key == "d") {
entry.description = trim(value);
entry.description = trim(value).substr(0, freqman_max_desc_size);
} else if (key == "f") {
entry.type = freqman_type::Single;
parse_int(value, entry.frequency_a);
@@ -492,7 +492,7 @@ freqman_entry FreqmanDB::operator[](Index index) const {
return entry;
else if (read_raw_) {
entry.type = freqman_type::Raw;
entry.description = trim(*line_text);
entry.description = trim(*line_text).substr(0, freqman_max_desc_size);
return entry;
}
}
+3
View File
@@ -162,6 +162,9 @@ std::string freqman_entry_get_step_string_short(freqman_index_t step);
* ensure app memory stability. */
constexpr size_t freqman_default_max_entries = 150;
/* Limiting description to 30 as specified by the format */
constexpr size_t freqman_max_desc_size = 30;
struct freqman_load_options {
/* Loads all entries when set to 0. */
size_t max_entries{freqman_default_max_entries};
+39 -4
View File
@@ -150,7 +150,9 @@ void MAX2837::init() {
}
void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) {
/* IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
Mode saved_mode = get_mode();
/* TX IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
// TX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,0,1 (5dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins .
@@ -172,7 +174,7 @@ void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) {
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
flush_one(Register::SPI_EN);
set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby.
set_mode(saved_mode); // restore original mode
}
enum class Mask { // There are class Mask ,and class mode with same names, but they are not same.
@@ -205,12 +207,18 @@ Mask mode_mask(const Mode mode) { // based on enum Mode cases, we set up the co
}
void MAX2837::set_mode(const Mode mode) { // We set up the 3 Logic Pins ENABLE, RXENABLE, TXENABLE accordingly to the max2837 mode case, that we want to set up .
_mode = mode;
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2837_rxenable.write(toUType(mask) & toUType(Mask::RxEnable));
gpio_max2837_txenable.write(toUType(mask) & toUType(Mask::TxEnable));
}
Mode MAX2837::get_mode() {
return _mode;
}
void MAX2837::flush() {
if (_dirty) {
for (size_t n = 0; n < reg_count; n++) {
@@ -324,14 +332,41 @@ bool MAX2837::set_frequency(const rf::Frequency lo_frequency) {
return true;
}
void MAX2837::set_rx_lo_iq_calibration(const size_t v) {
/*
void MAX2837::set_rx_lo_iq_calibration(const size_t v) { // Original code , rewritten below
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1;
_dirty[Register::RX_TOP_RX_BIAS] = 1;
_map.r.rxrf_2.iqerr_trim = v;
_dirty[Register::RXRF_2] = 1;
flush();
}
*/
void MAX2837::set_rx_LO_iq_phase_calibration(const size_t v) {
/* RX IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */
// RX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,1,0 (3dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
set_mode(Mode::Rx_Calibration); // write to ram 3 LOGIC Pins .
gpio_max283x_enable.output();
gpio_max2837_rxenable.output();
gpio_max2837_txenable.output();
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
flush_one(Register::SPI_EN);
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1; // reg 8 D9, RX LO IQ Phase calibration SPI control. Active when Address 8 D<9> = 1.
flush_one(Register::RX_TOP_RX_BIAS);
_map.r.rxrf_2.iqerr_trim = v; // reg 1 D9:D5, RX LO I/Q Phase SPI 5 bits Adjust
flush_one(Register::RXRF_2);
// Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated.
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default)
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
flush_one(Register::SPI_EN);
}
void MAX2837::set_rx_bias_trim(const size_t v) {
_map.r.rx_top_rx_bias.EN_Bias_Trim = 1;
+3 -1
View File
@@ -828,7 +828,7 @@ class MAX2837 : public MAX283x {
bool set_frequency(const rf::Frequency lo_frequency) override;
void set_rx_lo_iq_calibration(const size_t v) override;
void set_rx_LO_iq_phase_calibration(const size_t v) override;
void set_tx_LO_iq_phase_calibration(const size_t v) override;
void set_rx_bias_trim(const size_t v);
void set_vco_bias(const size_t v);
@@ -841,6 +841,7 @@ class MAX2837 : public MAX283x {
private:
spi::arbiter::Target& _target;
Mode _mode{Mode::Standby};
RegisterMap _map{initial_register_values};
DirtyRegisters<Register, reg_count> _dirty{};
@@ -851,6 +852,7 @@ class MAX2837 : public MAX283x {
reg_t read(const Register reg);
void flush();
Mode get_mode();
};
} // namespace max2837
+36 -3
View File
@@ -143,6 +143,8 @@ void MAX2839::init() {
}
void MAX2839::set_tx_LO_iq_phase_calibration(const size_t v) {
Mode saved_mode = get_mode();
/* IQ phase deg CAL adj (+4 ...-4) This IC in 64 steps (6 bits), 000000 = +4deg (Q lags I by 94degs, default), 011111 = +0deg, 111111 = -4deg (Q lags I by 86degs) */
// TX calibration , 2 x Logic pins , ENABLE, RXENABLE = 1,0, (2dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
@@ -164,7 +166,7 @@ void MAX2839::set_tx_LO_iq_phase_calibration(const size_t v) {
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable )
flush_one(Register::SPI_EN);
set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby.
set_mode(saved_mode); // restore original mode
}
enum class Mask {
@@ -196,11 +198,17 @@ Mask mode_mask(const Mode mode) {
}
void MAX2839::set_mode(const Mode mode) {
_mode = mode;
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2839_rxtx.write(toUType(mask) & toUType(Mask::RxTx));
}
Mode MAX2839::get_mode() {
return _mode;
}
void MAX2839::flush() {
if (_dirty) {
for (size_t n = 0; n < reg_count; n++) {
@@ -367,13 +375,38 @@ bool MAX2839::set_frequency(const rf::Frequency lo_frequency) {
return true;
}
void MAX2839::set_rx_lo_iq_calibration(const size_t v) {
/*
void MAX2839::set_rx_LO_iq_phase_calibration(const size_t v) { // Original code , rewritten below
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1;
_dirty[Register::RXRF_2] = 1;
_map.r.rxrf_1.iqerr_trim = v;
_dirty[Register::RXRF_1] = 1;
flush();
}*/
void MAX2839::set_rx_LO_iq_phase_calibration(const size_t v) {
/* RX IQ phase deg CAL adj (+4 ...-4) in 64 steps (6 bits), 000000 = +4deg (Q lags I by 94degs, default), 011111 = +0deg, 111111 = -4deg (Q lags I by 86degs) */
// RX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,1,0 (3dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1)
set_mode(Mode::Rx_Calibration); // write to ram 3 LOGIC Pins .
gpio_max283x_enable.output(); // max2839 has only 2 x pins + regs to decide mode.
gpio_max2839_rxtx.output(); // Here is combined rx & tx pin in one port.
_map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1)
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
flush_one(Register::SPI_EN);
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1; // reg 2 D<2> = 1, RX LO IQ calibration SPI control. Active when Address 2 D<2> = 1.
_dirty[Register::RXRF_2] = 1;
_map.r.rxrf_1.iqerr_trim = v;
_dirty[Register::RXRF_1] = 1;
flush();
_map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (CAL mode 1)
_map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1)
flush_one(Register::SPI_EN);
}
void MAX2839::set_rx_buff_vcm(const size_t v) {
+6 -4
View File
@@ -82,11 +82,11 @@ struct RXENABLE_Type {
static_assert(sizeof(RXENABLE_Type) == sizeof(reg_t), "RXENABLE_Type wrong size");
struct RXRF_1_Type {
reg_t LNAband : 1;
reg_t LNAband : 2; // Datasheet says D1:D0 , 2 bits, maybe D1 Rx_B, D0 Rx_A , (original code said wrongly ,reg_t LNAband : 1; that was of for max2837, not max2839 )
reg_t RESERVED0 : 1;
reg_t MIMOmode : 1;
reg_t iqerr_trim : 5;
reg_t RESERVED1 : 6;
reg_t iqerr_trim : 6; // Datasheet says D9_D4 , that means 6 bits, (original code said wrongly ,reg_t iqerr_trim : 5; )
reg_t RESERVED1 : 6; // we are using 16 bits , even top part mapping is not used
};
static_assert(sizeof(RXRF_1_Type) == sizeof(reg_t), "RXRF_1_Type wrong size");
@@ -689,7 +689,7 @@ class MAX2839 : public MAX283x {
void set_lpf_rf_bandwidth_rx(const uint32_t bandwidth_minimum) override;
void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override;
bool set_frequency(const rf::Frequency lo_frequency) override;
void set_rx_lo_iq_calibration(const size_t v) override;
void set_rx_LO_iq_phase_calibration(const size_t v) override;
void set_tx_LO_iq_phase_calibration(const size_t v) override;
void set_rx_buff_vcm(const size_t v) override;
@@ -700,6 +700,7 @@ class MAX2839 : public MAX283x {
private:
spi::arbiter::Target& _target;
Mode _mode{Mode::Standby};
RegisterMap _map{initial_register_values};
DirtyRegisters<Register, reg_count> _dirty{};
@@ -712,6 +713,7 @@ class MAX2839 : public MAX283x {
void flush();
void configure_rx_gain();
Mode get_mode();
};
} // namespace max2839
+1 -1
View File
@@ -125,7 +125,7 @@ class MAX283x {
virtual bool set_frequency(const rf::Frequency lo_frequency);
virtual void set_rx_lo_iq_calibration(const size_t v);
virtual void set_rx_LO_iq_phase_calibration(const size_t v);
virtual void set_tx_LO_iq_phase_calibration(const size_t v);
virtual void set_rx_buff_vcm(const size_t v);
+41
View File
@@ -31,6 +31,9 @@ using namespace std::literals;
const std::string_view center_freq_name = "center_frequency"sv;
const std::string_view sample_rate_name = "sample_rate"sv;
const std::string_view latitude_name = "latitude"sv;
const std::string_view longitude_name = "longitude"sv;
const std::string_view satinuse_name = "satinuse"sv;
fs::path get_metadata_path(const fs::path& capture_path) {
auto temp = capture_path;
@@ -54,6 +57,23 @@ Optional<File::Error> write_metadata_file(const fs::path& path, capture_metadata
if (error)
return error;
// add gps data if available
if (metadata.latitude != 0 && metadata.longitude != 0 && metadata.latitude < 200 && metadata.longitude < 200) {
error = f.write_line(std::string{latitude_name} + "=" +
to_string_decimal(metadata.latitude, 7));
if (error)
return error;
error = f.write_line(std::string{longitude_name} + "=" +
to_string_decimal(metadata.longitude, 7));
if (error)
return error;
error = f.write_line(std::string{satinuse_name} + "=" +
to_string_dec_uint(metadata.satinuse));
if (error)
return error;
}
return {};
}
@@ -77,6 +97,12 @@ Optional<capture_metadata> read_metadata_file(const fs::path& path) {
parse_int(cols[1], metadata.center_frequency);
else if (cols[0] == sample_rate_name)
parse_int(cols[1], metadata.sample_rate);
else if (cols[0] == latitude_name)
parse_float_meta(cols[1], metadata.latitude);
else if (cols[0] == longitude_name)
parse_float_meta(cols[1], metadata.longitude);
else if (cols[0] == satinuse_name)
parse_int(cols[1], metadata.satinuse);
else
continue;
}
@@ -86,3 +112,18 @@ Optional<capture_metadata> read_metadata_file(const fs::path& path) {
return metadata;
}
bool parse_float_meta(std::string_view str, float& out_val) {
out_val = {};
if (str.size() > max_parse_int_length)
return false;
// Copy onto the stack and null terminate.
char zstr[max_parse_int_length + 1];
std::memcpy(zstr, str.data(), str.size());
zstr[str.size()] = '\0';
errno = 0;
out_val = strtod(zstr, nullptr);
return (errno == 0);
}
+4
View File
@@ -29,6 +29,9 @@
struct capture_metadata {
rf::Frequency center_frequency;
uint32_t sample_rate;
float latitude = 0;
float longitude = 0;
uint8_t satinuse = 0;
};
std::filesystem::path get_metadata_path(const std::filesystem::path& capture_path);
@@ -36,4 +39,5 @@ std::filesystem::path get_metadata_path(const std::filesystem::path& capture_pat
Optional<File::Error> write_metadata_file(const std::filesystem::path& path, capture_metadata metadata);
Optional<capture_metadata> read_metadata_file(const std::filesystem::path& path);
bool parse_float_meta(std::string_view str, float& out_val);
#endif // __METADATA_FILE_HPP__
+4
View File
@@ -253,6 +253,10 @@ void set_tx_max283x_iq_phase_calibration(const size_t v) {
second_if->set_tx_LO_iq_phase_calibration(v);
}
void set_rx_max283x_iq_phase_calibration(const size_t v) {
second_if->set_rx_LO_iq_phase_calibration(v);
}
/*void enable(Configuration configuration) {
configure(configuration);
}
+1
View File
@@ -55,6 +55,7 @@ void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum);
void set_baseband_rate(const uint32_t rate);
void set_antenna_bias(const bool on);
void set_tx_max283x_iq_phase_calibration(const size_t v);
void set_rx_max283x_iq_phase_calibration(const size_t v);
/* Use ReceiverModel or TransmitterModel instead. */
// void enable(Configuration configuration);
+22 -2
View File
@@ -3,6 +3,7 @@
* Copyright (C) 2016 Furrtek
* Copyright (C) 2019 Elia Yehuda (z4ziggy)
* Copyright (C) 2023 Mark Thompson
* Copyright (C) 2024 u-foka
*
* This file is part of PortaPack.
*
@@ -106,7 +107,14 @@ void BtnGridView::on_tick_second() {
}
void BtnGridView::clear() {
// clear vector and release memory, not using swap since it's causing capture to glitch/fault
menu_items.clear();
for (auto& item : menu_item_views)
remove_child(item.get());
// clear vector and release memory, not using swap since it's causing capture to glitch/fault
menu_item_views.clear();
}
void BtnGridView::add_items(std::initializer_list<GridItem> new_items) {
@@ -207,11 +215,23 @@ void BtnGridView::on_focus() {
void BtnGridView::on_blur() {
#if 0
if (!keep_highlight)
item_view(highlighted_item - offset)->unhighlight();
if (!keep_highlight)
item_view(highlighted_item - offset)->unhighlight();
#endif
}
void BtnGridView::on_show() {
on_populate();
View::on_show();
}
void BtnGridView::on_hide() {
View::on_hide();
clear();
}
bool BtnGridView::on_key(const KeyEvent key) {
switch (key) {
case KeyEvent::Up:
+6
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2019 Elia Yehuda (z4ziggy)
* Copyright (C) 2024 u-foka
*
* This file is part of PortaPack.
*
@@ -73,10 +74,15 @@ class BtnGridView : public View {
void set_arrow_enabled(bool enabled);
void on_focus() override;
void on_blur() override;
void on_show() override;
void on_hide() override;
bool on_key(const KeyEvent event) override;
bool on_encoder(const EncoderEvent event) override;
bool blacklisted_app(GridItem new_item);
protected:
virtual void on_populate() = 0;
private:
int rows_{3};
void update_items();
+8 -8
View File
@@ -163,19 +163,19 @@ void RSSI::paint(Painter& painter) {
}
}
int16_t RSSI::get_min() {
uint8_t RSSI::get_min() {
return min_;
}
int16_t RSSI::get_avg() {
uint8_t RSSI::get_avg() {
return avg_;
}
int16_t RSSI::get_max() {
uint8_t RSSI::get_max() {
return max_;
}
int16_t RSSI::get_delta() {
uint8_t RSSI::get_delta() {
return max_ - min_;
}
@@ -213,19 +213,19 @@ void RSSI::on_statistics_update(const RSSIStatistics& statistics) {
set_dirty();
}
int16_t RSSIGraph::get_graph_min() {
uint8_t RSSIGraph::get_graph_min() {
return graph_min_;
}
int16_t RSSIGraph::get_graph_avg() {
uint8_t RSSIGraph::get_graph_avg() {
return graph_avg_;
}
int16_t RSSIGraph::get_graph_max() {
uint8_t RSSIGraph::get_graph_max() {
return graph_max_;
}
int16_t RSSIGraph::get_graph_delta() {
uint8_t RSSIGraph::get_graph_delta() {
return graph_max_ - graph_min_;
}
+12 -12
View File
@@ -50,10 +50,10 @@ class RSSI : public Widget {
}
// get last used/received min/avg/max/delta
int16_t get_min();
int16_t get_avg();
int16_t get_max();
int16_t get_delta();
uint8_t get_min();
uint8_t get_avg();
uint8_t get_max();
uint8_t get_delta();
void set_vertical_rssi(bool enabled);
void set_peak(bool enabled, size_t duration);
@@ -63,10 +63,10 @@ class RSSI : public Widget {
bool on_touch(const TouchEvent event) override;
private:
int16_t min_ = 0;
int16_t avg_ = 0;
int16_t max_ = 0;
int16_t peak_ = 0;
int8_t min_ = 0;
int8_t avg_ = 0;
int8_t max_ = 0;
int8_t peak_ = 0;
size_t peak_duration_ = 0;
bool instant_exec_{false};
@@ -115,10 +115,10 @@ class RSSIGraph : public Widget {
void on_hide() override;
void on_show() override;
// get whole graph_list min/avg/max/delta
int16_t get_graph_min();
int16_t get_graph_avg();
int16_t get_graph_max();
int16_t get_graph_delta();
uint8_t get_graph_min();
uint8_t get_graph_avg();
uint8_t get_graph_max();
uint8_t get_graph_delta();
private:
int16_t graph_min_ = 0;
+33 -20
View File
@@ -740,40 +740,49 @@ void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView&
/* ReceiversMenuView *****************************************************/
ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
ReceiversMenuView::ReceiversMenuView(NavigationView& nav)
: nav_(nav) {}
void ReceiversMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
add_item({"..", Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }});
add_item({"..", Color::light_grey(), &bitmap_icon_previous, [this]() { nav_.pop(); }});
}
add_apps(nav, *this, RX);
add_apps(nav_, *this, RX);
addExternalItems(nav, app_location_t::RX, *this);
addExternalItems(nav_, app_location_t::RX, *this);
}
/* TransmittersMenuView **************************************************/
TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
TransmittersMenuView::TransmittersMenuView(NavigationView& nav)
: nav_(nav) {}
void TransmittersMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
add_items({{"..", Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
add_items({{"..", Color::light_grey(), &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_apps(nav, *this, TX);
add_apps(nav_, *this, TX);
addExternalItems(nav, app_location_t::TX, *this);
addExternalItems(nav_, app_location_t::TX, *this);
}
/* UtilitiesMenuView *****************************************************/
UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav) {
UtilitiesMenuView::UtilitiesMenuView(NavigationView& nav)
: nav_(nav) {
set_max_rows(2); // allow wider buttons
}
void UtilitiesMenuView::on_populate() {
if (pmem::show_gui_return_icon()) {
add_items({{"..", Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
add_items({{"..", Color::light_grey(), &bitmap_icon_previous, [this]() { nav_.pop(); }}});
}
add_apps(nav, *this, UTILITIES);
add_apps(nav_, *this, UTILITIES);
addExternalItems(nav, app_location_t::UTILITIES, *this);
set_max_rows(2); // allow wider buttons
addExternalItems(nav_, app_location_t::UTILITIES, *this);
}
/* SystemMenuView ********************************************************/
@@ -790,15 +799,18 @@ void SystemMenuView::hackrf_mode(NavigationView& nav) {
});
}
SystemMenuView::SystemMenuView(NavigationView& nav) {
add_apps(nav, *this, HOME);
add_item({"HackRF", Color::cyan(), &bitmap_icon_hackrf, [this, &nav]() { hackrf_mode(nav); }});
SystemMenuView::SystemMenuView(NavigationView& nav)
: nav_(nav) {
set_max_rows(2); // allow wider buttons
set_arrow_enabled(false);
}
void SystemMenuView::on_populate() {
add_apps(nav_, *this, HOME);
add_item({"HackRF", Color::cyan(), &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
}
/* SystemView ************************************************************/
SystemView::SystemView(
@@ -861,6 +873,7 @@ NavigationView* SystemView::get_navigation_view() {
}
void SystemView::toggle_overlay() {
static uint8_t last_perf_counter_status = shared_memory.request_m4_performance_counter;
switch (++overlay_active) {
case 1:
this->add_child(&this->overlay);
@@ -879,7 +892,7 @@ void SystemView::toggle_overlay() {
case 3:
this->remove_child(&this->overlay2);
this->set_dirty();
shared_memory.request_m4_performance_counter = 0;
shared_memory.request_m4_performance_counter = last_perf_counter_status;
overlay_active = 0;
break;
}
+14 -4
View File
@@ -320,10 +320,6 @@ class BMPView : public View {
void focus() override;
private:
Text text_info{
{4 * 8, 284, 20 * 8, 16},
"Version " VERSION_STRING};
Button button_done{
{240, 0, 1, 1},
""};
@@ -333,18 +329,30 @@ class ReceiversMenuView : public BtnGridView {
public:
ReceiversMenuView(NavigationView& nav);
std::string title() const override { return "Receive"; };
private:
NavigationView& nav_;
void on_populate() override;
};
class TransmittersMenuView : public BtnGridView {
public:
TransmittersMenuView(NavigationView& nav);
std::string title() const override { return "Transmit"; };
private:
NavigationView& nav_;
void on_populate() override;
};
class UtilitiesMenuView : public BtnGridView {
public:
UtilitiesMenuView(NavigationView& nav);
std::string title() const override { return "Utilities"; };
private:
NavigationView& nav_;
void on_populate() override;
};
class SystemMenuView : public BtnGridView {
@@ -352,6 +360,8 @@ class SystemMenuView : public BtnGridView {
SystemMenuView(NavigationView& nav);
private:
NavigationView& nav_;
void on_populate() override;
void hackrf_mode(NavigationView& nav);
};
+12 -1
View File
@@ -205,6 +205,11 @@ void RecordView::start() {
return;
}
// check for geo data, if present append filename with _GEO
if (latitude != 0 && longitude != 0 && latitude < 200 && longitude < 200) {
base_path.append_filename(u"_GEO");
}
std::unique_ptr<stream::Writer> writer;
switch (file_type) {
case FileType::WAV: {
@@ -223,7 +228,7 @@ void RecordView::start() {
case FileType::RawS8:
case FileType::RawS16: {
const auto metadata_file_error = write_metadata_file(
get_metadata_path(base_path), {receiver_model.target_frequency(), sampling_rate});
get_metadata_path(base_path), {receiver_model.target_frequency(), sampling_rate, latitude, longitude, satinuse});
if (metadata_file_error.is_valid()) {
handle_error(metadata_file_error.value());
return;
@@ -342,6 +347,12 @@ void RecordView::trim_capture() {
trim_path = {};
}
void RecordView::on_gps(const GPSPosDataMessage* msg) {
latitude = msg->lat;
longitude = msg->lon;
satinuse = msg->satinuse;
}
void RecordView::handle_capture_thread_done(const File::Error error) {
stop();
if (error.code()) {
+12
View File
@@ -88,6 +88,7 @@ class RecordView : public View {
OversampleRate get_oversample_rate(uint32_t sample_rate);
void on_gps(const GPSPosDataMessage* msg);
// bool pitch_rssi_enabled = false;
// Time Stamp
@@ -95,6 +96,10 @@ class RecordView : public View {
bool filename_as_is = false;
rtc::RTC datetime{};
float latitude = 0; // for wardriwing with ext module
float longitude = 0;
uint8_t satinuse = 0; // to see if there was enough sats used or not
const std::filesystem::path filename_stem_pattern;
const std::filesystem::path folder;
FileType file_type;
@@ -147,6 +152,13 @@ class RecordView : public View {
const auto message = *reinterpret_cast<const CaptureThreadDoneMessage*>(p);
this->handle_capture_thread_done(message.error);
}};
MessageHandlerRegistration message_handler_gps{
Message::ID::GPSPosData,
[this](Message* const p) {
const auto message = static_cast<const GPSPosDataMessage*>(p);
this->on_gps(message);
}};
};
} /* namespace ui */
+48 -14
View File
@@ -211,6 +211,7 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) {
chprintf(chp, "ok\r\n");
}
// calculates the 1 byte rgb value, and add 32 to it, so it can be a printable character.
static char getChrFromRgb(uint8_t r, uint8_t g, uint8_t b) {
uint8_t chR = r >> 6; // 3bit
uint8_t chG = g >> 6; // 3bit
@@ -220,26 +221,36 @@ static char getChrFromRgb(uint8_t r, uint8_t g, uint8_t b) {
return res;
}
// keep track of a buffer, and sends only if full. not only line by line
static void screenbuffer_helper_add(BaseSequentialStream* chp, char* buffer, size_t& wp, char ch) {
buffer[wp++] = ch;
if (wp > USBSERIAL_BUFFERS_SIZE - 1) {
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, USBSERIAL_BUFFERS_SIZE);
wp = 0;
}
}
// sends only 1 byte (printable only) per pixel, so around 96 colors
static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv[]) {
(void)argc;
(void)argv;
auto evtd = getEventDispatcherInstance();
evtd->enter_shell_working_mode();
char buffer[USBSERIAL_BUFFERS_SIZE];
size_t wp = 0;
for (int y = 0; y < ui::screen_height; y++) {
std::array<ui::ColorRGB888, ui::screen_width> row;
portapack::display.read_pixels({0, y, ui::screen_width, 1}, row);
char buffer[242];
for (int i = 0; i < 240; ++i) {
buffer[i] = getChrFromRgb(row[i].r, row[i].g, row[i].b);
screenbuffer_helper_add(chp, buffer, wp, getChrFromRgb(row[i].r, row[i].g, row[i].b));
}
buffer[240] = '\r';
buffer[241] = '\n';
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 242);
screenbuffer_helper_add(chp, buffer, wp, '\r');
screenbuffer_helper_add(chp, buffer, wp, '\n');
}
if (wp > 0) {
// send remaining
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, wp);
}
evtd->exit_shell_working_mode();
chprintf(chp, "\r\nok\r\n");
}
@@ -894,8 +905,8 @@ static void cmd_cpld_read(BaseSequentialStream* chp, int argc, char* argv[]) {
}
static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotgps <lat> <lon> [altitude] [speed]\r\n";
if (argc < 2 || argc > 4) {
const char* usage = "usage: gotgps <lat> <lon> [altitude] [speed] [satinuse]\r\n";
if (argc < 2 || argc > 5) {
chprintf(chp, usage);
return;
}
@@ -903,21 +914,43 @@ static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
float lon = atof(argv[1]);
int32_t altitude = 0;
int32_t speed = 0;
uint8_t satinuse = 0;
if (argc >= 3) altitude = strtol(argv[2], NULL, 10);
if (argc >= 4) speed = strtol(argv[3], NULL, 10);
GPSPosDataMessage msg{lat, lon, altitude, speed};
if (argc >= 5) satinuse = strtol(argv[4], NULL, 10);
GPSPosDataMessage msg{lat, lon, altitude, speed, satinuse};
EventDispatcher::send_message(msg);
chprintf(chp, "ok\r\n");
}
static void cmd_gotorientation(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotorientation <angle>\r\n";
if (argc != 1) {
const char* usage = "usage: gotorientation <angle> [tilt]\r\n";
if (argc != 1 && argc != 2) {
chprintf(chp, usage);
return;
}
uint16_t angle = strtol(argv[0], NULL, 10);
OrientationDataMessage msg{angle};
int16_t tilt = 400;
if (argc >= 2) tilt = strtol(argv[1], NULL, 10);
OrientationDataMessage msg{angle, tilt};
EventDispatcher::send_message(msg);
chprintf(chp, "ok\r\n");
}
static void cmd_gotenv(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotenv <temperature> [humidity] [pressure] [light]\r\n";
if (argc < 1 || argc > 4) {
chprintf(chp, usage);
return;
}
float temp = atof(argv[0]);
float humi = 0;
float pressure = 0;
uint16_t light = 0;
if (argc > 1) humi = atof(argv[1]);
if (argc > 2) pressure = atof(argv[2]);
if (argc > 3) light = strtol(argv[3], NULL, 10);
EnvironmentDataMessage msg{temp, humi, pressure, light};
EventDispatcher::send_message(msg);
chprintf(chp, "ok\r\n");
}
@@ -1044,6 +1077,7 @@ static const ShellCommand commands[] = {
{"appstart", cmd_appstart},
{"gotgps", cmd_gotgps},
{"gotorientation", cmd_gotorientation},
{"gotenv", cmd_gotenv},
{"sysinfo", cmd_sysinfo},
{"radioinfo", cmd_radioinfo},
{"pmemreset", cmd_pmemreset},
+10 -10
View File
@@ -290,7 +290,7 @@ macro(DeclareTargets chunk_tag name)
DEPENDS ${PROJECT_NAME}.elf ${MAKE_IMAGE_CHUNK}
VERBATIM
)
set(BASEBAND_IMAGES ${BASEBAND_IMAGES} ${PROJECT_NAME}.img)
else()
@@ -434,12 +434,12 @@ set(MODE_CPPSRC
)
DeclareTargets(PNFM nfm_audio)
### No op
set(MODE_CPPSRC
proc_noop.cpp
)
DeclareTargets(PNOP no_operation)
#### No op
#
#set(MODE_CPPSRC
# proc_noop.cpp
#)
#DeclareTargets(PNOP no_operation)
### OOK
@@ -519,7 +519,7 @@ set(MODE_CPPSRC
)
DeclareTargets(PWFM wfm_audio)
### SubGhz Decoders
### SubGhz Decoders
set(MODE_CPPSRC
proc_subghzd.cpp
@@ -554,7 +554,7 @@ set(MODE_INCDIR
)
set(MODE_CPPSRC
sd_over_usb/proc_sd_over_usb.cpp
sd_over_usb/scsi.c
sd_over_usb/diskio.c
sd_over_usb/sd_over_usb.c
@@ -672,7 +672,7 @@ set(BASEBAND_IMAGES ${BASEBAND_IMAGES} terminator.img)
#######################################################################
project(baseband)
add_custom_command(
OUTPUT ${PROJECT_NAME}.img
COMMAND cat ${BASEBAND_IMAGES} > ${PROJECT_NAME}.img
+23 -17
View File
@@ -162,14 +162,6 @@ static void rx_error() {
disable();
}
void init() {
gpdma_channel_i2s0_tx.set_handlers(tx_transfer_complete, tx_error);
gpdma_channel_i2s0_rx.set_handlers(rx_transfer_complete, rx_error);
// LPC_GPDMA->SYNC |= (1 << gpdma_rx_peripheral);
// LPC_GPDMA->SYNC |= (1 << gpdma_tx_peripheral);
}
static void configure_tx() {
const auto peripheral = reinterpret_cast<uint32_t>(&LPC_I2S0->TXFIFO);
const auto control_value = control_tx(transfer_bytes);
@@ -194,22 +186,32 @@ static void configure_rx() {
}
}
void configure() {
configure_tx();
configure_rx();
static void enable_tx() {
const auto gpdma_config_tx = config_tx();
gpdma_channel_i2s0_tx.configure(lli_tx_loop[0], gpdma_config_tx);
gpdma_channel_i2s0_tx.enable();
}
void enable() {
const auto gpdma_config_tx = config_tx();
static void enable_rx() {
const auto gpdma_config_rx = config_rx();
gpdma_channel_i2s0_tx.configure(lli_tx_loop[0], gpdma_config_tx);
gpdma_channel_i2s0_rx.configure(lli_rx_loop[0], gpdma_config_rx);
gpdma_channel_i2s0_tx.enable();
gpdma_channel_i2s0_rx.enable();
}
void init_audio_out() {
gpdma_channel_i2s0_tx.set_handlers(tx_transfer_complete, tx_error);
// LPC_GPDMA->SYNC |= (1 << gpdma_tx_peripheral);
configure_tx();
enable_tx();
}
void init_audio_in() {
gpdma_channel_i2s0_rx.set_handlers(rx_transfer_complete, rx_error);
// LPC_GPDMA->SYNC |= (1 << gpdma_rx_peripheral);
configure_rx();
enable_rx();
}
void disable() {
gpdma_channel_i2s0_tx.disable();
gpdma_channel_i2s0_rx.disable();
@@ -217,6 +219,10 @@ void disable() {
void shrink_tx_buffer(bool shrink) {
single_tx_buffer = shrink;
if (transfers_per_buffer == 1)
return;
if (single_tx_buffer)
lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[0]);
else
+2 -3
View File
@@ -43,9 +43,8 @@ using buffer_t = buffer_t<sample_t>;
namespace dma {
void init();
void configure();
void enable();
void init_audio_in();
void init_audio_out();
void disable();
void shrink_tx_buffer(bool shrink);
+1 -6
View File
@@ -28,13 +28,8 @@
#include "gpdma.hpp"
#include "audio_dma.hpp"
static void init() {
audio::dma::init();
audio::dma::configure();
audio::dma::enable();
// Audio DMA initialization was moved to baseband proc's that actually use DMA audio, to save memory.
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
}
+4
View File
@@ -23,6 +23,8 @@
#include "proc_afskrx.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_dma.hpp"
#include "event_m4.hpp"
void AFSKRxProcessor::execute(const buffer_c8_t& buffer) {
@@ -181,6 +183,8 @@ void AFSKRxProcessor::configure(const AFSKRxConfigureMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<AFSKRxProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -22,6 +22,7 @@
#include "proc_am_audio.hpp"
#include "audio_output.hpp"
#include "audio_dma.hpp"
#include "event_m4.hpp"
@@ -112,6 +113,8 @@ void NarrowbandAMAudio::capture_config(const CaptureConfigMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<NarrowbandAMAudio>()};
event_dispatcher.run();
return 0;
+4
View File
@@ -23,6 +23,8 @@
#include "proc_aprsrx.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_dma.hpp"
#include "event_m4.hpp"
#include "stdio.h"
@@ -244,6 +246,8 @@ void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<APRSRxProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -24,6 +24,7 @@
#include "portapack_shared_memory.hpp"
#include "sine_table_int8.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <cstdint>
@@ -139,6 +140,8 @@ void AudioTXProcessor::sample_rate_config(const SampleRateConfigMessage& message
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<AudioTXProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -25,6 +25,7 @@
#include "sine_table_int8.hpp"
#include "tonesets.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <cstdint>
@@ -167,6 +168,8 @@ void MicTXProcessor::on_message(const Message* const msg) {
}
int main() {
audio::dma::init_audio_in();
EventDispatcher event_dispatcher{std::make_unique<MicTXProcessor>()};
event_dispatcher.run();
return 0;
+4
View File
@@ -24,6 +24,8 @@
#include "sine_table_int8.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_dma.hpp"
#include "event_m4.hpp"
#include <cstdint>
@@ -174,6 +176,8 @@ void NarrowbandFMAudio::capture_config(const CaptureConfigMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<NarrowbandFMAudio>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -27,6 +27,7 @@
#include "dsp_iir_config.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <algorithm>
#include <cmath>
@@ -530,6 +531,8 @@ uint32_t POCSAGProcessor::getRate() const {
//
// ====================================================================
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<POCSAGProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -26,6 +26,7 @@
#include "proc_pocsag2.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <algorithm>
#include <cmath>
@@ -416,6 +417,8 @@ void POCSAGProcessor::send_packet() {
/* main **************************************************/
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<POCSAGProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -27,6 +27,7 @@
#include "event_m4.hpp"
#include "audio_output.hpp"
#include "audio_dma.hpp"
SondeProcessor::SondeProcessor() {
decim_0.configure(taps_11k0_decim_0.taps);
@@ -141,6 +142,8 @@ void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message)
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<SondeProcessor>()};
event_dispatcher.run();
+3
View File
@@ -23,6 +23,7 @@
#include "proc_tones.hpp"
#include "sine_table_int8.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <cstdint>
@@ -154,6 +155,8 @@ void TonesProcessor::on_message(const Message* const p) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<TonesProcessor>()};
event_dispatcher.run();
return 0;
+3
View File
@@ -26,6 +26,7 @@
#include "audio_output.hpp"
#include "dsp_fft.hpp"
#include "event_m4.hpp"
#include "audio_dma.hpp"
#include <cstdint>
@@ -188,6 +189,8 @@ void WidebandFMAudio::capture_config(const CaptureConfigMessage& message) {
}
int main() {
audio::dma::init_audio_out();
EventDispatcher event_dispatcher{std::make_unique<WidebandFMAudio>()};
event_dispatcher.run();
return 0;
@@ -20,6 +20,7 @@
*/
#include "proc_wideband_spectrum.hpp"
#include "audio_dma.hpp"
#include "event_m4.hpp"
@@ -82,6 +83,8 @@ void WidebandSpectrum::on_message(const Message* const msg) {
}
int main() {
audio::dma::init_audio_out(); // for AudioRX app (enables audio output while this baseband image is running)
EventDispatcher event_dispatcher{std::make_unique<WidebandSpectrum>()};
event_dispatcher.run();
return 0;
+3 -3
View File
@@ -22,12 +22,12 @@
#ifndef __RSSI_STATS_COLLECTOR_H__
#define __RSSI_STATS_COLLECTOR_H__
#include "rssi.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include "rssi.hpp"
#include "message.hpp"
class RSSIStatisticsCollector {
public:
template <typename Callback>
+34 -8
View File
@@ -120,6 +120,7 @@ class Message {
SubGhzDData = 62,
GPSPosData = 63,
OrientationData = 64,
EnvironmentData = 65,
MAX
};
@@ -132,10 +133,10 @@ class Message {
};
struct RSSIStatistics {
uint32_t accumulator{0};
uint32_t min{0};
uint32_t max{0};
uint32_t count{0};
uint16_t accumulator{0};
uint8_t min{0};
uint8_t max{0};
uint16_t count{0};
};
class RSSIStatisticsMessage : public Message {
@@ -1312,27 +1313,52 @@ class GPSPosDataMessage : public Message {
float lat = 200.0,
float lon = 200.0,
int32_t altitude = 0,
int32_t speed = 0)
int32_t speed = 0,
uint8_t satinuse = 0)
: Message{ID::GPSPosData},
lat{lat},
lon{lon},
altitude{altitude},
speed{speed} {
speed{speed},
satinuse{satinuse} {
}
float lat = 200.0;
float lon = 200.0;
int32_t altitude = 0;
int32_t speed = 0;
uint8_t satinuse = 0;
};
class OrientationDataMessage : public Message {
public:
constexpr OrientationDataMessage(
uint16_t angle = 400)
uint16_t angle = 400,
int16_t tilt = 400)
: Message{ID::OrientationData},
angle{angle} {
angle{angle},
tilt{tilt} {
}
uint16_t angle = 400; //>360 -> no orientation set
int16_t tilt = 400;
};
class EnvironmentDataMessage : public Message {
public:
constexpr EnvironmentDataMessage(
float temperature = 0,
float humidity = 0,
float pressure = 0,
uint16_t light = 0)
: Message{ID::EnvironmentData},
temperature{temperature},
humidity{humidity},
pressure{pressure},
light{light} {
}
float temperature = 0; // celsius
float humidity = 0; // percent (rh)
float pressure = 0; // hpa
uint16_t light = 0; // lux
};
#endif /*__MESSAGE_H__*/
+58 -27
View File
@@ -435,6 +435,7 @@ void defaults() {
set_recon_load_hamradios(true);
set_recon_match_mode(0);
set_recon_repeat_recorded(false);
set_recon_repeat_recorded_file_mode(false); // false delete repeater , true keep repeated
set_recon_repeat_amp(false);
set_recon_repeat_gain(35);
set_recon_repeat_nb(3);
@@ -784,38 +785,63 @@ void set_clkout_freq(uint16_t freq) {
}
/* Recon app */
enum recon_config_bits {
RC_UNUSED_BIT = 63, // just a reminder that this is a 64-bit field
RC_AUTOSAVE_FREQS = 31,
RC_AUTOSTART_RECON = 30,
RC_CONTINUOUS = 29,
RC_CLEAR_OUTPUT = 28,
RC_LOAD_FREQS = 27,
RC_LOAD_RANGES = 26,
RC_UPDATE_RANGES = 25,
RC_LOAD_HAMRADIOS = 24,
RC_MATCH_MODE = 23,
RC_AUTO_RECORD_LOCKED = 22,
RC_REPEAT_RECORDED = 21,
RC_REPEAT_AMP = 20,
RC_LOAD_REPEATERS = 19,
RC_REPEAT_FILE_MODE = 18,
};
bool check_recon_config_bit(uint8_t rc_bit) {
return ((data->recon_config >> rc_bit) & 1) != 0;
}
void set_recon_config_bit(uint8_t rc_bit, bool v) {
auto bit_mask = 1LL << rc_bit;
data->recon_config = v ? (data->recon_config | bit_mask) : (data->recon_config & ~bit_mask);
}
bool recon_autosave_freqs() {
return (data->recon_config & 0x80000000UL) ? true : false;
return check_recon_config_bit(RC_AUTOSAVE_FREQS);
}
bool recon_autostart_recon() {
return (data->recon_config & 0x40000000UL) ? true : false;
return check_recon_config_bit(RC_AUTOSTART_RECON);
}
bool recon_continuous() {
return (data->recon_config & 0x20000000UL) ? true : false;
return check_recon_config_bit(RC_CONTINUOUS);
}
bool recon_clear_output() {
return (data->recon_config & 0x10000000UL) ? true : false;
return check_recon_config_bit(RC_CLEAR_OUTPUT);
}
bool recon_load_freqs() {
return (data->recon_config & 0x08000000UL) ? true : false;
return check_recon_config_bit(RC_LOAD_FREQS);
}
bool recon_load_ranges() {
return (data->recon_config & 0x04000000UL) ? true : false;
return check_recon_config_bit(RC_LOAD_RANGES);
}
bool recon_update_ranges_when_recon() {
return (data->recon_config & 0x02000000UL) ? true : false;
return check_recon_config_bit(RC_UPDATE_RANGES);
}
bool recon_load_hamradios() {
return (data->recon_config & 0x01000000UL) ? true : false;
return check_recon_config_bit(RC_LOAD_HAMRADIOS);
}
bool recon_match_mode() {
return (data->recon_config & 0x00800000UL) ? true : false;
return check_recon_config_bit(RC_MATCH_MODE);
}
bool recon_auto_record_locked() {
return (data->recon_config & 0x00400000UL) ? true : false;
return check_recon_config_bit(RC_AUTO_RECORD_LOCKED);
}
bool recon_repeat_recorded() {
return (data->recon_config & 0x00200000UL) ? true : false;
return check_recon_config_bit(RC_REPEAT_RECORDED);
}
int8_t recon_repeat_nb() {
return data->recon_repeat_nb;
@@ -827,44 +853,46 @@ uint8_t recon_repeat_delay() {
return data->recon_repeat_delay;
}
bool recon_repeat_amp() {
return (data->recon_config & 0x00100000UL) ? true : false;
return check_recon_config_bit(RC_REPEAT_AMP);
}
bool recon_load_repeaters() {
return (data->recon_config & 0x00080000UL) ? true : false;
return check_recon_config_bit(RC_LOAD_REPEATERS);
}
bool recon_repeat_recorded_file_mode() {
return check_recon_config_bit(RC_REPEAT_FILE_MODE);
}
void set_recon_autosave_freqs(const bool v) {
data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31);
set_recon_config_bit(RC_AUTOSAVE_FREQS, v);
}
void set_recon_autostart_recon(const bool v) {
data->recon_config = (data->recon_config & ~0x40000000UL) | (v << 30);
set_recon_config_bit(RC_AUTOSTART_RECON, v);
}
void set_recon_continuous(const bool v) {
data->recon_config = (data->recon_config & ~0x20000000UL) | (v << 29);
set_recon_config_bit(RC_CONTINUOUS, v);
}
void set_recon_clear_output(const bool v) {
data->recon_config = (data->recon_config & ~0x10000000UL) | (v << 28);
set_recon_config_bit(RC_CLEAR_OUTPUT, v);
}
void set_recon_load_freqs(const bool v) {
data->recon_config = (data->recon_config & ~0x08000000UL) | (v << 27);
set_recon_config_bit(RC_LOAD_FREQS, v);
}
void set_recon_load_ranges(const bool v) {
data->recon_config = (data->recon_config & ~0x04000000UL) | (v << 26);
set_recon_config_bit(RC_LOAD_RANGES, v);
}
void set_recon_update_ranges_when_recon(const bool v) {
data->recon_config = (data->recon_config & ~0x02000000UL) | (v << 25);
set_recon_config_bit(RC_UPDATE_RANGES, v);
}
void set_recon_load_hamradios(const bool v) {
data->recon_config = (data->recon_config & ~0x01000000UL) | (v << 24);
set_recon_config_bit(RC_LOAD_HAMRADIOS, v);
}
void set_recon_match_mode(const bool v) {
data->recon_config = (data->recon_config & ~0x00800000UL) | (v << 23);
set_recon_config_bit(RC_MATCH_MODE, v);
}
void set_recon_auto_record_locked(const bool v) {
data->recon_config = (data->recon_config & ~0x00400000UL) | (v << 22);
set_recon_config_bit(RC_AUTO_RECORD_LOCKED, v);
}
void set_recon_repeat_recorded(const bool v) {
data->recon_config = (data->recon_config & ~0x00200000UL) | (v << 21);
set_recon_config_bit(RC_REPEAT_RECORDED, v);
}
void set_recon_repeat_nb(const int8_t v) {
data->recon_repeat_nb = v;
@@ -876,10 +904,13 @@ void set_recon_repeat_delay(const uint8_t v) {
data->recon_repeat_delay = v;
}
void set_recon_repeat_amp(const bool v) {
data->recon_config = (data->recon_config & ~0x00100000UL) | (v << 20);
set_recon_config_bit(RC_REPEAT_AMP, v);
}
void set_recon_load_repeaters(const bool v) {
data->recon_config = (data->recon_config & ~0x00080000UL) | (v << 19);
set_recon_config_bit(RC_LOAD_REPEATERS, v);
}
void set_recon_repeat_recorded_file_mode(const bool v) {
set_recon_config_bit(RC_REPEAT_FILE_MODE, v);
}
/* UI Config 2 */
@@ -298,6 +298,7 @@ bool recon_load_ranges();
bool recon_update_ranges_when_recon();
bool recon_auto_record_locked();
bool recon_repeat_recorded();
bool recon_repeat_recorded_file_mode();
int8_t recon_repeat_nb();
int8_t recon_repeat_gain();
bool recon_repeat_amp();
@@ -313,6 +314,7 @@ void set_recon_load_ranges(const bool v);
void set_recon_update_ranges_when_recon(const bool v);
void set_recon_auto_record_locked(const bool v);
void set_recon_repeat_recorded(const bool v);
void set_recon_repeat_recorded_file_mode(const bool v);
void set_recon_repeat_nb(const int8_t v);
void set_recon_repeat_gain(const int8_t v);
void set_recon_repeat_amp(const bool v);
+1
View File
@@ -73,6 +73,7 @@ struct image_tag_t {
char c[4];
};
constexpr image_tag_t image_tag_none{0, 0, 0, 0};
constexpr image_tag_t image_tag_acars{'P', 'A', 'C', 'A'};
constexpr image_tag_t image_tag_adsb_rx{'P', 'A', 'D', 'R'};
constexpr image_tag_t image_tag_afsk_rx{'P', 'A', 'F', 'R'};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

+82
View File
@@ -0,0 +1,82 @@
# Drone Analog FPV Channels
# https://oscarliang.com/fpv-channels/
f=5865000000,d=FPV Ch A-1
f=5845000000,d=FPV Ch A-2
f=5825000000,d=FPV Ch A-3
f=5805000000,d=FPV Ch A-4
f=5785000000,d=FPV Ch A-5
f=5765000000,d=FPV Ch A-6
f=5745000000,d=FPV Ch A-7
f=5725000000,d=FPV Ch A-8
f=5733000000,d=FPV Ch B-1
f=5752000000,d=FPV Ch B-2
f=5771000000,d=FPV Ch B-3
f=5790000000,d=FPV Ch B-4
f=5809000000,d=FPV Ch B-5
f=5828000000,d=FPV Ch B-6
f=5847000000,d=FPV Ch B-7
f=5866000000,d=FPV Ch B-8
f=5705000000,d=FPV Ch E-1
f=5685000000,d=FPV Ch E-2
f=5665000000,d=FPV Ch E-3
f=5645000000,d=FPV Ch E-4
f=5885000000,d=FPV Ch E-5
f=5905000000,d=FPV Ch E-6
f=5925000000,d=FPV Ch E-7
f=5945000000,d=FPV Ch E-8
f=5740000000,d=FPV Ch F-1
f=5760000000,d=FPV Ch F-2
f=5780000000,d=FPV Ch F-3
f=5800000000,d=FPV Ch F-4
f=5820000000,d=FPV Ch F-5
f=5840000000,d=FPV Ch F-6
f=5860000000,d=FPV Ch F-7
f=5880000000,d=FPV Ch F-8
f=5658000000,d=FPV Ch R-1
f=5695000000,d=FPV Ch R-2
f=5732000000,d=FPV Ch R-3
f=5769000000,d=FPV Ch R-4
f=5806000000,d=FPV Ch R-5
f=5843000000,d=FPV Ch R-6
f=5880000000,d=FPV Ch R-7
f=5917000000,d=FPV Ch R-8
f=5362000000,d=FPV Ch D-1
f=5399000000,d=FPV Ch D-2
f=5436000000,d=FPV Ch D-3
f=5473000000,d=FPV Ch D-4
f=5510000000,d=FPV Ch D-5
f=5547000000,d=FPV Ch D-6
f=5584000000,d=FPV Ch D-7
f=5621000000,d=FPV Ch D-8
f=5325000000,d=FPV Ch U-1
f=5348000000,d=FPV Ch U-2
f=5366000000,d=FPV Ch U-3
f=5384000000,d=FPV Ch U-4
f=5402000000,d=FPV Ch U-5
f=5420000000,d=FPV Ch U-6
f=5438000000,d=FPV Ch U-7
f=5456000000,d=FPV Ch U-8
f=5474000000,d=FPV Ch O-1
f=5492000000,d=FPV Ch O-2
f=5510000000,d=FPV Ch O-3
f=5528000000,d=FPV Ch O-4
f=5546000000,d=FPV Ch O-5
f=5564000000,d=FPV Ch O-6
f=5582000000,d=FPV Ch O-7
f=5600000000,d=FPV Ch O-8
f=5333000000,d=FPV Ch L-1
f=5373000000,d=FPV Ch L-2
f=5413000000,d=FPV Ch L-3
f=5453000000,d=FPV Ch L-4
f=5493000000,d=FPV Ch L-5
f=5533000000,d=FPV Ch L-6
f=5573000000,d=FPV Ch L-7
f=5613000000,d=FPV Ch L-8
f=5653000000,d=FPV Ch H-1
f=5693000000,d=FPV Ch H-2
f=5733000000,d=FPV Ch H-3
f=5773000000,d=FPV Ch H-4
f=5813000000,d=FPV Ch H-5
f=5853000000,d=FPV Ch H-6
f=5893000000,d=FPV Ch H-7
f=5933000000,d=FPV Ch H-8