From 27dc37713b699f5fb616903c09312c9408beac52 Mon Sep 17 00:00:00 2001 From: Bernd Herzog Date: Sat, 17 Feb 2024 10:38:09 +0100 Subject: [PATCH 01/98] added crc32 command to usb shell (#1911) --- .../usb_serial_shell_filesystem.cpp | 33 +++++++++++++++++++ .../usb_serial_shell_filesystem.hpp | 6 ++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/firmware/application/usb_serial_shell_filesystem.cpp b/firmware/application/usb_serial_shell_filesystem.cpp index 821c30193..db3231fdb 100644 --- a/firmware/application/usb_serial_shell_filesystem.cpp +++ b/firmware/application/usb_serial_shell_filesystem.cpp @@ -26,6 +26,8 @@ #include "string_format.hpp" #include +#include "crc.hpp" + static File* shell_file = nullptr; static bool report_on_error(BaseSequentialStream* chp, File::Error& error) { @@ -371,3 +373,34 @@ void cmd_sd_write_binary(BaseSequentialStream* chp, int argc, char* argv[]) { chprintf(chp, "ok\r\n"); } + +void cmd_sd_crc32(BaseSequentialStream* chp, int argc, char* argv[]) { + if (argc != 1) { + chprintf(chp, "usage: crc32 \r\n"); + return; + } + + auto path = path_from_string8(argv[0]); + File* crc_file = new File(); + auto error = crc_file->open(path, true, false); + if (report_on_error(chp, error)) return; + + uint8_t buffer[64]; + CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff}; + + while (true) { + auto bytes_read = crc_file->read(buffer, 64); + if (report_on_error(chp, bytes_read)) return; + + if (bytes_read.value() > 0) { + crc.process_bytes((void*)buffer, bytes_read.value()); + } + + if (64 != bytes_read.value()) { + chprintf(chp, "CRC32: 0x%08X\r\n", crc.checksum()); + return; + } + } + + delete crc_file; +} diff --git a/firmware/application/usb_serial_shell_filesystem.hpp b/firmware/application/usb_serial_shell_filesystem.hpp index 9b98ae5b6..2bd81d1e2 100644 --- a/firmware/application/usb_serial_shell_filesystem.hpp +++ b/firmware/application/usb_serial_shell_filesystem.hpp @@ -42,6 +42,7 @@ void cmd_sd_read(BaseSequentialStream* chp, int argc, char* argv[]); void cmd_sd_read_binary(BaseSequentialStream* chp, int argc, char* argv[]); void cmd_sd_write(BaseSequentialStream* chp, int argc, char* argv[]); void cmd_sd_write_binary(BaseSequentialStream* chp, int argc, char* argv[]); +void cmd_sd_crc32(BaseSequentialStream* chp, int argc, char* argv[]); static std::filesystem::path path_from_string8(char* path) { std::wstring_convert, char16_t> conv; @@ -62,6 +63,7 @@ static std::filesystem::path path_from_string8(char* path) { {"ftell", cmd_sd_tell}, \ {"fread", cmd_sd_read}, \ {"frb", cmd_sd_read_binary}, \ - {"fwrite", cmd_sd_write}, \ - {"fwb", cmd_sd_write_binary} + {"fwrite", cmd_sd_write}, \ + {"fwb", cmd_sd_write_binary}, \ + {"crc32", cmd_sd_crc32} // clang-format on From 948e0395743c8bfc3264ef2415d093a10b9a377a Mon Sep 17 00:00:00 2001 From: notComposer Date: Sun, 18 Feb 2024 00:44:31 +0800 Subject: [PATCH 02/98] fix shift back in screenshot and mayhem hub (#1910) * fix_shift_back * clean up * gitignore * remove the workaround in notpad cuz it's been fixed in this PR * format * add credit for mark * 2024 --- .gitignore | 4 ++- firmware/application/apps/ui_text_editor.cpp | 4 --- firmware/common/portapack_io.hpp | 32 +++++++++++++++----- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index cc292cb38..a40570cad 100644 --- a/.gitignore +++ b/.gitignore @@ -68,9 +68,11 @@ CMakeFiles/ .DS_Store /firmware/CMakeCache.txt -# Python env/ venv +# Python env/ venv and cache env/ venv/ +**/__pycache__/ +*.pyc # Other *.bak diff --git a/firmware/application/apps/ui_text_editor.cpp b/firmware/application/apps/ui_text_editor.cpp index a1584853e..fdf4a0de4 100644 --- a/firmware/application/apps/ui_text_editor.cpp +++ b/firmware/application/apps/ui_text_editor.cpp @@ -27,8 +27,6 @@ #include "log_file.hpp" #include "string_format.hpp" -#include "portapack_persistent_memory.hpp" - using namespace portapack; namespace fs = std::filesystem; @@ -556,8 +554,6 @@ void TextEditorView::open_file(const fs::path& path) { viewer.set_file(*file_); } - portapack::persistent_memory::set_apply_fake_brightness(false); // work around to resolve the display issue in notepad app. not elegant i know, so TODO. - refresh_ui(); } diff --git a/firmware/common/portapack_io.hpp b/firmware/common/portapack_io.hpp index 8fa45d8b6..a23627a21 100644 --- a/firmware/common/portapack_io.hpp +++ b/firmware/common/portapack_io.hpp @@ -2,6 +2,7 @@ * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyleft (ɔ) 2024 zxkmm under GPL license * Copyright (C) 2024 u-foka + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -147,7 +148,7 @@ class IO { void lcd_write_pixel(ui::Color pixel) { if (get_dark_cover()) { - darken_color(pixel, get_brightness()); // Darken the pixel color + shift_color(pixel, get_brightness(), false); // Darken the pixel color } lcd_write_data(pixel.v); } @@ -158,7 +159,7 @@ class IO { void lcd_write_pixels(ui::Color pixel, size_t n) { if (get_dark_cover()) { - darken_color(pixel, get_brightness()); // Darken the pixel color + shift_color(pixel, get_brightness(), false); // Darken the pixel color } while (n--) { lcd_write_data(pixel.v); @@ -167,7 +168,7 @@ class IO { void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) { if (get_dark_cover()) { - darken_color(pixel, get_brightness()); // Darken the pixel color + shift_color(pixel, get_brightness(), false); // Darken the pixel color } auto v = pixel.v; n >>= 3; @@ -331,7 +332,7 @@ class IO { addr(1); /* Set up for data phase (most likely after a command) */ } - void darken_color(ui::Color& pixel, uint8_t darken_level_shift) { + void shift_color(ui::Color& pixel, uint8_t shift_level, bool shift_left) { // TODO: 1. do we need edge control? // currently didn't see and issue without edge control // but maybe hurts screen hardware without one? @@ -343,9 +344,15 @@ class IO { uint16_t g = (pixel.v >> 5) & 0x3F; // Extract green uint16_t b = pixel.v & 0x1F; // Extract blue - r = r >> darken_level_shift; // Darken red - g = g >> darken_level_shift; // Darken green - b = b >> darken_level_shift; // Darken blue + if (shift_left) { // Shfting + r = r << shift_level; + g = g << shift_level; + b = b << shift_level; + } else if (!shift_left) { + r = r >> shift_level; + g = g >> shift_level; + b = b >> shift_level; + } pixel.v = (r << 11) | (g << 5) | b; // Combine back to color, check UI::color for the color layout } @@ -417,7 +424,16 @@ class IO { halPolledDelay(18); // 90ns const auto value_low = data_read(); - return (value_high << 8) | value_low; + uint32_t original_value = (value_high << 8) | value_low; + + if (get_dark_cover()) { + ui::Color pixel; + pixel.v = original_value; + shift_color(pixel, get_brightness(), true); + original_value = pixel.v; + } + + return original_value; } void io_write(const bool address, const uint_fast16_t value) { From 3499d2fa759f6b1e08cdea577ec0ba2fd7621615 Mon Sep 17 00:00:00 2001 From: Noah Axon Date: Sat, 17 Feb 2024 12:24:11 -0600 Subject: [PATCH 03/98] Fix Recon Modulation/Bandwidth presets (#1913) --- sdcard/FREQMAN/RECON.TXT | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sdcard/FREQMAN/RECON.TXT b/sdcard/FREQMAN/RECON.TXT index d1008e0a7..c5ae9cfaa 100644 --- a/sdcard/FREQMAN/RECON.TXT +++ b/sdcard/FREQMAN/RECON.TXT @@ -1,22 +1,22 @@ -a=150000,b=285000,m=AM,bw=DSB,s=5kHz,d=Longwave broadcast band|BCB (EU) -a=525000,b=1605000,m=AM,bw=DSB,s=5kHz,d=AM broadcast band|BCB (EU & J) -a=530000,b=1710000,m=AM,bw=DSB,s=5kHz,d=AM broadcast band|BCB (US) -a=1800000,b=29700000,m=WFM,bw=16k,d=Amateur_radio|Amateur -a=26900000,b=27400000,m=WFM,bw=16k,d=Citizens_band_radio|Citizens band -a=28000000,b=30000000,m=WFM,bw=16k,d=Amateur_radio|Amateur -a=29000000,b=54000000,m=WFM,bw=16k,d=Land mobile -a=50000000,b=54000000,m=WFM,bw=16k,d=Amateur_radio|Amateur -a=65000000,b=85000000,m=WFM,bw=16k,d=Land mobile (EU) -a=108000000,b=136000000,m=WFM,bw=16k,d=Aircraft -a=120000000,b=160000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (EU) -a=132000000,b=174000000,m=WFM,bw=16k,s=50kHz,d=Land mobile -a=142000000,b=170000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J) -a=144000000,b=148000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur -a=216000000,b=222000000,m=WFM,bw=16k,s=50kHz,d=Land mobile -a=222000000,b=225000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur -a=335000000,b=384000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J) -a=406000000,b=512000000,m=WFM,bw=16k,s=50kHz,d=Land mobile -a=450000000,b=470000000,m=WFM,bw=16k,s=50kHz,d=Land mobile (J) -a=430000000,b=450000000,m=WFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur -a=806000000,b=947000000,m=WFM,bw=16k,s=50kHz,d=Land mobile -a=1200000000,b=1600000000,m=WFM,bw=16k,s=50kHz,d=Amateur|Land mobile|GPS +a=150000,b=285000,m=AM,bw=DSB 9k,s=5kHz,d=Longwave broadcast band|BCB (EU) +a=525000,b=1605000,m=AM,bw=DSB 9k,s=5kHz,d=AM broadcast band|BCB (EU & J) +a=530000,b=1710000,m=AM,bw=DSB 9k,s=5kHz,d=AM broadcast band|BCB (US) +a=1800000,b=29700000,m=AM,bw=LSB-3k,d=Amateur_radio|Amateur +a=26900000,b=27400000,m=AM,bw=DSB 9k,d=Citizens_band_radio|Citizens band +a=28000000,b=30000000,m=AM,bw=USB+3k,d=Amateur_radio|Amateur +a=29000000,b=54000000,m=AM,bw=DSB 9k,d=Land mobile +a=50000000,b=54000000,m=NFM,bw=16k,d=Amateur_radio|Amateur +a=65000000,b=85000000,m=NFM,bw=16k,d=Land mobile (EU) +a=108000000,b=136000000,m=NFM,bw=16k,d=Aircraft +a=120000000,b=160000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (EU) +a=132000000,b=174000000,m=NFM,bw=16k,s=50kHz,d=Land mobile +a=142000000,b=170000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J) +a=144000000,b=148000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur +a=216000000,b=222000000,m=NFM,bw=16k,s=50kHz,d=Land mobile +a=222000000,b=225000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur +a=335000000,b=384000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J) +a=406000000,b=512000000,m=NFM,bw=16k,s=50kHz,d=Land mobile +a=450000000,b=470000000,m=NFM,bw=16k,s=50kHz,d=Land mobile (J) +a=430000000,b=450000000,m=NFM,bw=16k,s=50kHz,d=Amateur_radio|Amateur +a=806000000,b=947000000,m=NFM,bw=16k,s=50kHz,d=Land mobile +a=1200000000,b=1600000000,m=NFM,bw=16k,s=50kHz,d=Amateur|Land mobile|GPS From a1f7010e08b60415645c3981f550d280bf91b073 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 17 Feb 2024 18:44:06 -0600 Subject: [PATCH 04/98] Optimized fake brightness code (#1915) --- firmware/common/portapack_io.hpp | 52 ++++++++++++-------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/firmware/common/portapack_io.hpp b/firmware/common/portapack_io.hpp index a23627a21..c6ffe2666 100644 --- a/firmware/common/portapack_io.hpp +++ b/firmware/common/portapack_io.hpp @@ -35,6 +35,21 @@ // #include "portapack_persistent_memory.hpp" +// Darkened pixel bit mask for each possible shift value. +static const uint16_t darken_mask[4] = { + 0b1111111111111111, // RrrrrGgggggBbbbb + 0b0111101111101111, // 0Rrrr0Ggggg0Bbbb + 0b0011100111100111, // 00Rrr00Gggg00Bbb + 0b0001100011100011 // 000Rr000Ggg000Bb +}; + +// To darken, dividing each color level R/G/B by 2^shift. +#define DARKENED_PIXEL(pixel, shift) ((pixel >> shift) & darken_mask[shift]) + +// To un-darken, multiply each color level by 2^shift (might still be darker that before since some bits may have been lost above). +// This function will only be called when the pixel has previously been darkened, so no masking is needed. +#define UNDARKENED_PIXEL(pixel, shift) (pixel << shift) + namespace portapack { class IO { @@ -148,7 +163,7 @@ class IO { void lcd_write_pixel(ui::Color pixel) { if (get_dark_cover()) { - shift_color(pixel, get_brightness(), false); // Darken the pixel color + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); } lcd_write_data(pixel.v); } @@ -159,7 +174,7 @@ class IO { void lcd_write_pixels(ui::Color pixel, size_t n) { if (get_dark_cover()) { - shift_color(pixel, get_brightness(), false); // Darken the pixel color + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); } while (n--) { lcd_write_data(pixel.v); @@ -168,7 +183,7 @@ class IO { void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) { if (get_dark_cover()) { - shift_color(pixel, get_brightness(), false); // Darken the pixel color + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); } auto v = pixel.v; n >>= 3; @@ -332,31 +347,6 @@ class IO { addr(1); /* Set up for data phase (most likely after a command) */ } - void shift_color(ui::Color& pixel, uint8_t shift_level, bool shift_left) { - // TODO: 1. do we need edge control? - // currently didn't see and issue without edge control - // but maybe hurts screen hardware without one? - - // TODO: 2. de-color mode for accessibility - // TODO: 3. high contrast mode for accessibility - - uint16_t r = (pixel.v >> 11) & 0x1F; // Extract red - uint16_t g = (pixel.v >> 5) & 0x3F; // Extract green - uint16_t b = pixel.v & 0x1F; // Extract blue - - if (shift_left) { // Shfting - r = r << shift_level; - g = g << shift_level; - b = b << shift_level; - } else if (!shift_left) { - r = r >> shift_level; - g = g >> shift_level; - b = b >> shift_level; - } - - pixel.v = (r << 11) | (g << 5) | b; // Combine back to color, check UI::color for the color layout - } - // void high_contrast(ui::Color& pixel, size_t contrast_level_shift) { // TODO // uint16_t r = (pixel.v >> 11) & 0x1F; // uint16_t g = (pixel.v >> 5) & 0x3F; @@ -427,12 +417,8 @@ class IO { uint32_t original_value = (value_high << 8) | value_low; if (get_dark_cover()) { - ui::Color pixel; - pixel.v = original_value; - shift_color(pixel, get_brightness(), true); - original_value = pixel.v; + original_value = UNDARKENED_PIXEL(original_value, get_brightness()); } - return original_value; } From cd80da58d8458e3d04572d571a5fb4e5765b0cee Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 18 Feb 2024 12:02:42 -0600 Subject: [PATCH 05/98] Improved flash image validation (#1916) --- .../application/apps/ui_flash_utility.cpp | 30 ++++++++++++++++--- .../application/apps/ui_flash_utility.hpp | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/firmware/application/apps/ui_flash_utility.cpp b/firmware/application/apps/ui_flash_utility.cpp index 639f707d8..a91a39511 100644 --- a/firmware/application/apps/ui_flash_utility.cpp +++ b/firmware/application/apps/ui_flash_utility.cpp @@ -28,27 +28,49 @@ namespace ui { static const char16_t* firmware_folder = u"/FIRMWARE"; +// Firmware image validation +static const char* hackrf_magic = "HACKRFFW"; +#define FIRMWARE_INFO_AREA_OFFSET 0x400 +#define FIRST_CHECKSUM_NIGHTLY 240125 + Thread* FlashUtilityView::thread{nullptr}; static constexpr size_t max_filename_length = 26; bool valid_firmware_file(std::filesystem::path::string_type path) { File firmware_file; + bool require_checksum{false}; uint32_t read_buffer[128]; - uint32_t checksum{(uint32_t)~FLASH_EXPECTED_CHECKSUM}; // initializing to invalid checksum in case file can't be read + uint32_t checksum{FLASH_CHECKSUM_ERROR}; // initializing to invalid checksum in case file can't be read + + static_assert((FIRMWARE_INFO_AREA_OFFSET % sizeof(read_buffer)) == 0, "Read buffer size must divide evenly into FIRMWARE_INFO_AREA_OFFSET"); // test read of the whole file just to validate checksum (baseband flash code will re-read when flashing) auto result = firmware_file.open(path.c_str()); if (!result.is_valid()) { checksum = 0; - for (uint32_t i = 0; i < FLASH_ROM_SIZE / sizeof(read_buffer); i++) { + for (uint32_t offset = 0; offset < FLASH_ROM_SIZE; offset += sizeof(read_buffer)) { auto readResult = firmware_file.read(&read_buffer, sizeof(read_buffer)); - // if file is smaller than 1MB, assume it's a downgrade to an old FW version and ignore the checksum if ((!readResult) || (readResult.value() != sizeof(read_buffer))) { - checksum = FLASH_EXPECTED_CHECKSUM; + // File was smaller than 1MB: + // If version is such that the file SHOULD have been 1MB, call it a checksum error (otherwise say it's OK). + checksum = (require_checksum) ? FLASH_CHECKSUM_ERROR : FLASH_EXPECTED_CHECKSUM; break; } + // Did we just read the firmware info area? + if (offset == FIRMWARE_INFO_AREA_OFFSET) { + // If there's no info area (missing HACKRFFW signature), it could be an ancient FW version (so skipping check) + if (memcmp(read_buffer, hackrf_magic, 8) == 0) { + char* version_string = (char*)&read_buffer[4]; + + // Require a 1MB firmware image with a valid checksum if release version >=v2.x or nightly >n_240125 + if (((version_string[0] == 'v') && (std::atoi(&version_string[1]) >= 2)) || + ((version_string[0] == 'n') && (version_string[1] == '_') && (std::atoi(&version_string[2]) >= FIRST_CHECKSUM_NIGHTLY))) + require_checksum = true; + } + } + checksum += simple_checksum((uint32_t)read_buffer, sizeof(read_buffer)); } } diff --git a/firmware/application/apps/ui_flash_utility.hpp b/firmware/application/apps/ui_flash_utility.hpp index de03ebcc4..50a97c84a 100644 --- a/firmware/application/apps/ui_flash_utility.hpp +++ b/firmware/application/apps/ui_flash_utility.hpp @@ -35,6 +35,7 @@ #define FLASH_ROM_SIZE 1048576 #define FLASH_STARTING_ADDRESS 0x00000000 #define FLASH_EXPECTED_CHECKSUM 0x00000000 +#define FLASH_CHECKSUM_ERROR 0xFFFFFFFF namespace ui { From 4b83fd8a40c5a746841c9477648570c58a3c481d Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:30:14 +0100 Subject: [PATCH 06/98] Updating the videos from people about hackrf (#1918) The latest series from sasquash looks promising to engage beginners :) also will do some tracking with grabify to check engagement --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bb74d92e9..bc8aa1df4 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw # What is this? -If you are new to *HackRF+PortaPack+Mayhem*, check this video: +If you are new to *HackRF+PortaPack+Mayhem*, check these: -[![Beginner's Guide To The HackRF & Portapak With Mayhem](https://img.youtube.com/vi/H-bqdWfbhpg/0.jpg)](https://www.youtube.com/watch?v=H-bqdWfbhpg) +[HackRF 101 : Everything You Need to Know to Get Started!](https://grabify.link/C0J6ZR) -For people familiar with the [Flipper Zero](https://github.com/flipperdevices/flipperzero-firmware), this one might be interesting:
[What is the HackRF One Portapack H2+?](https://www.youtube.com/watch?v=alrFbY5vxt4) +[Beginner's Guide To The HackRF & Portapak With Mayhem](https://grabify.link/5MU2VH) [What is the HackRF One Portapack H2+?](https://grabify.link/9UZGEW) # Frequently Asked Questions From e4da8b979e8845740a704c3221bba348b81fdcc0 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:02:11 +0100 Subject: [PATCH 07/98] Update bug_report.md (#1929) --- .github/ISSUE_TEMPLATE/bug_report.md | 81 ++++++++++++++++------------ 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ab806e548..a2ed3b3a8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,35 +1,48 @@ ---- name: Bug report -about: Create a report to help us improve the software -title: '' -labels: bug -assignees: '' - ---- - ----- - -(Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases) - ----- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Tap on '....' -3. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Affected versions** -Please write any difference related with the Expected behavior, on the following versions: -* Latest Stable release: -* Latest Nightly release: -* Previous working release: - -**Additional** -If the bug is difficult to explain, additionally to the text please include images and videos. +description: File a bug reports regarding the firmware. +labels: ['bug'] +body: +- type: markdown + attributes: + value: | + Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Mayhem firmware. + Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases +- type: textarea + id: description + attributes: + label: Describe the bug. + description: "A clear and concise description of what the bug is." + validations: + required: true +- type: textarea + id: repro + attributes: + label: Reproduction + description: "How can this bug be reproduced?" + placeholder: | + 1. Switch on... + 2. Press button '....' + 3. Wait for the end of the universe + 4. It burns + validations: + required: true +- type: textarea + id: expected + attributes: + label: Expected behavior + description: "A clear and concise description of what you expected to happen" + placeholder: | + 1. Generates file on... + 2. I get a cheeseburger... + validations: + required: true +- type: input + id: target + attributes: + label: Environment/versions + description: Specify extra details about versions and environments affected +- type: textarea + id: anything-else + attributes: + label: Anything else? + description: Let us know if you have anything else to share. From 9ed8ad590312cdb3f22c4d97f09362cd1fe24fae Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:04:52 +0100 Subject: [PATCH 08/98] Create config.yml --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..7827a57e3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Need help? + url: https://discord.com/invite/tuwVMv3 + about: For any question regarding on how to use Mayhem firmware. From 1172175cc8df263fcfdb36eeb94311ec011fe608 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:06:04 +0100 Subject: [PATCH 09/98] Rename bug_report.md to 01_bug_report.yml --- .github/ISSUE_TEMPLATE/{bug_report.md => 01_bug_report.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{bug_report.md => 01_bug_report.yml} (100%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/01_bug_report.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/01_bug_report.yml From 57ccdb0044dc099754b541d590c631ec3e2ef2bf Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:11:13 +0100 Subject: [PATCH 10/98] Update and rename feature_request.md to feature_request.yml --- .github/ISSUE_TEMPLATE/feature_request.md | 20 ------------------ .github/ISSUE_TEMPLATE/feature_request.yml | 24 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 20 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 2a266e5ac..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. Remember that adding stuff is always possible, but time is a limited resource for everyone. Check the wiki for more information how to compile the firmware and try to explore modifying the code yourself. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional** -If the suggestion is difficult to explain, additionally to the text please include images and videos. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..4196dc81a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,24 @@ +name: Feature Request +description: For feature requests regarding the firmware. +labels: ['feature request'] +body: +- type: markdown + attributes: + value: | + Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions. + Please try the latest nightly release before submitting this, make sure it has not been implemented already. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases +- type: textarea + id: proposal + attributes: + label: "Description of the feature you're suggesting." + description: | + Please describe your feature request in as many details as possible. + - Describe what it should do. + - Note whether it is to extend existing functionality or introduce new functionality. + validations: + required: true +- type: textarea + id: anything-else + attributes: + label: Anything else? + description: Let us know if you have anything else to share. From 9c86e15ddbe8ccc84536fa30265804140b6810e3 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:12:20 +0100 Subject: [PATCH 11/98] Rename feature_request.yml to 02_feature_request.yml --- .../{feature_request.yml => 02_feature_request.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{feature_request.yml => 02_feature_request.yml} (100%) diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/02_feature_request.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.yml rename to .github/ISSUE_TEMPLATE/02_feature_request.yml From 9c848a6215619bc6a4242ba9ac6b3cf2c3ace216 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:13:23 +0100 Subject: [PATCH 12/98] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7827a57e3..dd916995c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Need help? + - name: Need more help? url: https://discord.com/invite/tuwVMv3 - about: For any question regarding on how to use Mayhem firmware. + about: For any question that does not fit as an issue, check our discord. From 762512b7dc0a6cb7e284c62df53152433881dfc3 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:13:54 +0100 Subject: [PATCH 13/98] Rename problem-upgrading-the-firmware.md to 03_problem-upgrading-the-firmware.md --- ...ading-the-firmware.md => 03_problem-upgrading-the-firmware.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{problem-upgrading-the-firmware.md => 03_problem-upgrading-the-firmware.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md b/.github/ISSUE_TEMPLATE/03_problem-upgrading-the-firmware.md similarity index 100% rename from .github/ISSUE_TEMPLATE/problem-upgrading-the-firmware.md rename to .github/ISSUE_TEMPLATE/03_problem-upgrading-the-firmware.md From 5ae97d47f1080a6119dda9b4b2272ed72caecb67 Mon Sep 17 00:00:00 2001 From: jLynx Date: Sun, 25 Feb 2024 07:28:44 +0000 Subject: [PATCH 14/98] Fixed existing dir check (#1933) --- firmware/application/usb_serial_shell_filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/usb_serial_shell_filesystem.cpp b/firmware/application/usb_serial_shell_filesystem.cpp index db3231fdb..b16dc1c74 100644 --- a/firmware/application/usb_serial_shell_filesystem.cpp +++ b/firmware/application/usb_serial_shell_filesystem.cpp @@ -99,7 +99,7 @@ void cmd_sd_mkdir(BaseSequentialStream* chp, int argc, char* argv[]) { auto path = path_from_string8(argv[0]); - if (!std::filesystem::is_directory(path)) { + if (std::filesystem::is_directory(path)) { chprintf(chp, "directory already exists.\r\n"); return; } From 86c326ef12f28772c3062fe04265305da3730e83 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:50:11 +0100 Subject: [PATCH 15/98] Update README.md (#1937) Adding a warning --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc8aa1df4..6758f3394 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ -> [!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] +> Recently, we have become aware of certain individuals distributing prepackaged packages of Mayhem for a fee, and we want to bring this to your attention to ensure the integrity and security of our project. +> +> We would like to clarify that none of the contributors to Mayhem receive any monetary compensation for their efforts. All the work put into this project is driven by passion and hobby, and we are committed to providing the community with an open-source solution that remains free of charge. +> +> __IF YOU'VE PAID FOR MAYHEM OR ANY PREPACKAGED PACKAGES, YOU'RE BEING SCAMMED.__ Seek a refund from your card company and report the issue immediately. +> The only legitimate link leading to our repositories is the organization [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware). Please ensure that any download or access to our software is done exclusively through these trusted sources. # PortaPack Mayhem From 3bf689f33940888df0612358f8716ec99b04df79 Mon Sep 17 00:00:00 2001 From: Dima Danylevskyi Date: Thu, 7 Mar 2024 08:37:41 +0200 Subject: [PATCH 16/98] Add FPV analog frequenies to FREQMAN (#1940) --- sdcard/FREQMAN/FPV_ANALOG.TXT | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 sdcard/FREQMAN/FPV_ANALOG.TXT diff --git a/sdcard/FREQMAN/FPV_ANALOG.TXT b/sdcard/FREQMAN/FPV_ANALOG.TXT new file mode 100644 index 000000000..dcf21487f --- /dev/null +++ b/sdcard/FREQMAN/FPV_ANALOG.TXT @@ -0,0 +1,80 @@ +f=5865000000,d=CH-A-1 +f=5845000000,d=CH-A-2 +f=5825000000,d=CH-A-3 +f=5805000000,d=CH-A-4 +f=5785000000,d=CH-A-5 +f=5765000000,d=CH-A-6 +f=5745000000,d=CH-A-7 +f=5725000000,d=CH-A-8 +f=5733000000,d=CH-B-1 +f=5752000000,d=CH-B-2 +f=5771000000,d=CH-B-3 +f=5790000000,d=CH-B-4 +f=5809000000,d=CH-B-5 +f=5828000000,d=CH-B-6 +f=5847000000,d=CH-B-7 +f=5866000000,d=CH-B-8 +f=5705000000,d=CH-E-1 +f=5685000000,d=CH-E-2 +f=5665000000,d=CH-E-3 +f=5645000000,d=CH-E-4 +f=5885000000,d=CH-E-5 +f=5905000000,d=CH-E-6 +f=5925000000,d=CH-E-7 +f=5945000000,d=CH-E-8 +f=5740000000,d=CH-F-1 +f=5760000000,d=CH-F-2 +f=5780000000,d=CH-F-3 +f=5800000000,d=CH-F-4 +f=5820000000,d=CH-F-5 +f=5840000000,d=CH-F-6 +f=5860000000,d=CH-F-7 +f=5880000000,d=CH-F-8 +f=5658000000,d=CH-R-1 +f=5695000000,d=CH-R-2 +f=5732000000,d=CH-R-3 +f=5769000000,d=CH-R-4 +f=5806000000,d=CH-R-5 +f=5843000000,d=CH-R-6 +f=5880000000,d=CH-R-7 +f=5917000000,d=CH-R-8 +f=5362000000,d=CH-D-1 +f=5399000000,d=CH-D-2 +f=5436000000,d=CH-D-3 +f=5473000000,d=CH-D-4 +f=5510000000,d=CH-D-5 +f=5547000000,d=CH-D-6 +f=5584000000,d=CH-D-7 +f=5621000000,d=CH-D-8 +f=5325000000,d=CH-U-1 +f=5348000000,d=CH-U-2 +f=5366000000,d=CH-U-3 +f=5384000000,d=CH-U-4 +f=5402000000,d=CH-U-5 +f=5420000000,d=CH-U-6 +f=5438000000,d=CH-U-7 +f=5456000000,d=CH-U-8 +f=5474000000,d=CH-O-1 +f=5492000000,d=CH-O-2 +f=5510000000,d=CH-O-3 +f=5528000000,d=CH-O-4 +f=5546000000,d=CH-O-5 +f=5564000000,d=CH-O-6 +f=5582000000,d=CH-O-7 +f=5600000000,d=CH-O-8 +f=5333000000,d=CH-L-1 +f=5373000000,d=CH-L-2 +f=5413000000,d=CH-L-3 +f=5453000000,d=CH-L-4 +f=5493000000,d=CH-L-5 +f=5533000000,d=CH-L-6 +f=5573000000,d=CH-L-7 +f=5613000000,d=CH-L-8 +f=5653000000,d=CH-H-1 +f=5693000000,d=CH-H-2 +f=5733000000,d=CH-H-3 +f=5773000000,d=CH-H-4 +f=5813000000,d=CH-H-5 +f=5853000000,d=CH-H-6 +f=5893000000,d=CH-H-7 +f=5933000000,d=CH-H-8 \ No newline at end of file From 9e9dd3a5211e90253c036adac99e641f9b97075c Mon Sep 17 00:00:00 2001 From: Totoo Date: Thu, 7 Mar 2024 07:42:58 +0100 Subject: [PATCH 17/98] Dynamic usb buffer fill for screenframeshort (#1935) * fully fill usb serial buffer * Update usb_serial_shell.cpp * Added a comment, to trigger wf --- firmware/application/usb_serial_shell.cpp | 27 ++++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 1d39e5e07..0f952f751 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -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 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"); } From c28087ac4468d8be7d49672256058bb388e7daed Mon Sep 17 00:00:00 2001 From: not tre mann <24917424+zxkmm@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:49:17 +0800 Subject: [PATCH 18/98] cheat code protect in pacman app (#1945) --- .../application/external/pacman/playfield.hpp | 79 +++++++++++++++---- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/firmware/application/external/pacman/playfield.hpp b/firmware/application/external/pacman/playfield.hpp index 64ef77e61..d0b4f1719 100644 --- a/firmware/application/external/pacman/playfield.hpp +++ b/firmware/application/external/pacman/playfield.hpp @@ -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) { From 73137891c4411b9563d162a44af1e9ffa8652d90 Mon Sep 17 00:00:00 2001 From: not tre mann <24917424+zxkmm@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:50:49 +0800 Subject: [PATCH 19/98] change sun bitmap to make it more like a sun (#1946) --- .gitignore | 4 ++++ firmware/application/bitmap.hpp | 8 ++++---- firmware/graphics/icon_brightness.png | Bin 292 -> 4352 bytes 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index a40570cad..52f03525b 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index b2e536379..9e2b36337 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -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, diff --git a/firmware/graphics/icon_brightness.png b/firmware/graphics/icon_brightness.png index 67766915c61e09aa096330b95c6a178f83f0460e..0ea3ac6a97ebef39bb6d1ddca6a0ad9e648dffa8 100644 GIT binary patch literal 4352 zcmeHLe{2)i9X}^PLRw1|36!=>IUOAR2gar4b#ZNKI1EXa{ur-r4!J zRhlBL|HaYs``&w>_j%v%=Y8Kdxja>0x5!y^ZxKNd&TwsL3G{bat#Ar_mtOl9g6=eK z3M=7o8BquifOJeE92N$eW0ale$S3k)Y%{cJU|Sfg-Rqca_glffFK6!p`+*!L4{Wz1 zk8ncY4UGf41p0%})L&%xdJAmpQ)vIxf@Lue^^3xhdXjUwS(nEL>sgK$S&ztiNw-_{ z_(h%rv}50hM;24(zHlF~Y*K^4`fxBv>V~GMaZC`I?)BRPweQrIJn=}w)712W`A_=g zmgnYmZ1JBhD|vq5f$1w++4jCtUaeiSa@OR(c63%gy|m!&*s33`oLn_f@b0!bLmQ!cOXEqw4~*`P3ZDD0e8X{;Lj z=9$z7cw?;Q!??27zi{5}KQ#44m-)QCYVU!AeY==T70U!|?b(B^XTREcj9q#9vE7I3 zyjx0UygF$rRr2wpRnvXFuU~zk>HX8~J?~Za{`1Gi+)D>HY?mC~mTjvlzbU=7_xDS? zyRPr}W0<_&>o0ZhOW)n%opt%*y$nE5y-H?-|1e_1~-uRnG@(%yV!#+B9A{(g4Bdwu!a_AlSBZRiX(|1Nay>Vp2S zuI@d5EdA-Vn~p7A#w$Je)FjBkjM~^_HboYTl9q5GS&L#gtb?K%TDtgCC3)~%5QnW|h+RFM&ZAc0LpW)ksaO3VZ( zn^y$e8fGZchL~#tR1@S;P%|*eyLcB%S7+2Vj#^MeRv5A(E(z7-DBvkTwV0+ZGE6$1 zcBMTo&4@8>K@b?0V>pfm1f6P6nkYjjQ?o6KEJp~ZBtz9rRZEfzZ_H-0G>p?*jkt}GB?iZF0!UNfpL-16RFx62#`tE<*x`(J1hyOI zAA=r>-39|H5)nh1)M{-S4h1O7Us2X1RTgcNC5x z#YcN(QOQ8%<+03q5TZE+voz013XM2HpplHCQ6cJ8+&<2xvd%%Qst*S!&c%+5)W?yj zXhtGHEmo7QnURS`HGvyUWQpc3X9XWC2pm`L6?iTioz1rl8!1RQi_y2aW_uiB5rYOsre-v1T0B4vSKZ<12wW!_nJ9!z47&~2 z;l`ml{2=QW*=$@ET||>rrTu@Qt;<7J03MFKR!zbF?ez~MF!So$DnvYEo6p^VNNrv?EHYA+*$m9I{@{>Cgaj~Laqt9#-+fxz!TXu zA=kJR7#DaVyZ&!-6^*=3;UxSOl!lk3eFG{l-0+u)l&2WzTcyF5h@ zcNAOAL3DM`guwzc9H}n2l0P|rPT9)65$hiY&xJ!(jsBDScYf~NMBe$t;2eEYO>;?& zRDAB@tmDojPP4QByNcr9mORC)dDjQK{_)1CrFRxSq-)MS8xL>(w)<^jaN6oiv7W;E z6EmDU+O`t2FK(RL^u^A<{dq-4=ezm$rOy+e^&HxoIJe`=JMO=5qv&|q;+|jY2Uxyr z{>;nIPTM+X_lZwRf0fzp&aZ5LeAlZ#+xD=db-wqRug_!S=+#>V=Iqt8>W+M7`A&qZ L>q0LrZ0`6sz;D@n delta 265 zcmV+k0rviYBBTP4B!BBkL_t(IPo-0V4ZpM$B)W;Z0UKC1s2k`6 zc-MRtkS``BAu0dI{rx>Pvyl}-STk*mX*HOs5O^W5RRUC70Ax|^GJp{~34x1ZJA8ZK zo_#J$oN?aABynXB@^XSnS`YwbQ_T^(_W+9?9I#n6QTgKmNPilDZbA|Z;N=a}b#bsn zKo7QxX;%=ijn6VND$2bh>2PMHxkAtZvlMezY-=E(+wC6&4`3Q0pg(SU3%OJ=k*?=$ zyf~Fn6SFb0t$2)lO!^p0kEEbZe@K&`a%pTJ^^Bu$tBm#gFDL}n-}wzO$AD|cX4BIE P0000 Date: Thu, 7 Mar 2024 10:00:53 -0600 Subject: [PATCH 20/98] Update FPV_ANALOG.TXT (#1951) * Include FPV in freq description * Added comment referencing source of this data --- sdcard/FREQMAN/FPV_ANALOG.TXT | 162 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/sdcard/FREQMAN/FPV_ANALOG.TXT b/sdcard/FREQMAN/FPV_ANALOG.TXT index dcf21487f..3cfe8c8f0 100644 --- a/sdcard/FREQMAN/FPV_ANALOG.TXT +++ b/sdcard/FREQMAN/FPV_ANALOG.TXT @@ -1,80 +1,82 @@ -f=5865000000,d=CH-A-1 -f=5845000000,d=CH-A-2 -f=5825000000,d=CH-A-3 -f=5805000000,d=CH-A-4 -f=5785000000,d=CH-A-5 -f=5765000000,d=CH-A-6 -f=5745000000,d=CH-A-7 -f=5725000000,d=CH-A-8 -f=5733000000,d=CH-B-1 -f=5752000000,d=CH-B-2 -f=5771000000,d=CH-B-3 -f=5790000000,d=CH-B-4 -f=5809000000,d=CH-B-5 -f=5828000000,d=CH-B-6 -f=5847000000,d=CH-B-7 -f=5866000000,d=CH-B-8 -f=5705000000,d=CH-E-1 -f=5685000000,d=CH-E-2 -f=5665000000,d=CH-E-3 -f=5645000000,d=CH-E-4 -f=5885000000,d=CH-E-5 -f=5905000000,d=CH-E-6 -f=5925000000,d=CH-E-7 -f=5945000000,d=CH-E-8 -f=5740000000,d=CH-F-1 -f=5760000000,d=CH-F-2 -f=5780000000,d=CH-F-3 -f=5800000000,d=CH-F-4 -f=5820000000,d=CH-F-5 -f=5840000000,d=CH-F-6 -f=5860000000,d=CH-F-7 -f=5880000000,d=CH-F-8 -f=5658000000,d=CH-R-1 -f=5695000000,d=CH-R-2 -f=5732000000,d=CH-R-3 -f=5769000000,d=CH-R-4 -f=5806000000,d=CH-R-5 -f=5843000000,d=CH-R-6 -f=5880000000,d=CH-R-7 -f=5917000000,d=CH-R-8 -f=5362000000,d=CH-D-1 -f=5399000000,d=CH-D-2 -f=5436000000,d=CH-D-3 -f=5473000000,d=CH-D-4 -f=5510000000,d=CH-D-5 -f=5547000000,d=CH-D-6 -f=5584000000,d=CH-D-7 -f=5621000000,d=CH-D-8 -f=5325000000,d=CH-U-1 -f=5348000000,d=CH-U-2 -f=5366000000,d=CH-U-3 -f=5384000000,d=CH-U-4 -f=5402000000,d=CH-U-5 -f=5420000000,d=CH-U-6 -f=5438000000,d=CH-U-7 -f=5456000000,d=CH-U-8 -f=5474000000,d=CH-O-1 -f=5492000000,d=CH-O-2 -f=5510000000,d=CH-O-3 -f=5528000000,d=CH-O-4 -f=5546000000,d=CH-O-5 -f=5564000000,d=CH-O-6 -f=5582000000,d=CH-O-7 -f=5600000000,d=CH-O-8 -f=5333000000,d=CH-L-1 -f=5373000000,d=CH-L-2 -f=5413000000,d=CH-L-3 -f=5453000000,d=CH-L-4 -f=5493000000,d=CH-L-5 -f=5533000000,d=CH-L-6 -f=5573000000,d=CH-L-7 -f=5613000000,d=CH-L-8 -f=5653000000,d=CH-H-1 -f=5693000000,d=CH-H-2 -f=5733000000,d=CH-H-3 -f=5773000000,d=CH-H-4 -f=5813000000,d=CH-H-5 -f=5853000000,d=CH-H-6 -f=5893000000,d=CH-H-7 -f=5933000000,d=CH-H-8 \ No newline at end of file +# 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 From 908c0e2cd50f6fc1023e64fead9f182e4849be0c Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:18:08 -0600 Subject: [PATCH 21/98] Fix compiler warning (#1952) --- firmware/application/external/calculator/ivt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/external/calculator/ivt.hpp b/firmware/application/external/calculator/ivt.hpp index f258bb0b8..8259c369a 100644 --- a/firmware/application/external/calculator/ivt.hpp +++ b/firmware/application/external/calculator/ivt.hpp @@ -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--; } From 2648f18b12835dee9ce96057a857910bf6b8a6b8 Mon Sep 17 00:00:00 2001 From: Totoo Date: Thu, 7 Mar 2024 17:22:24 +0100 Subject: [PATCH 22/98] External sensor tester app (#1949) * added tilt * added extsensors app * added icon * Added EnvironmentData to ExtSensor app and message.hpp * Added gotenv command --- firmware/application/external/external.cmake | 6 ++ firmware/application/external/external.ld | 9 ++ .../application/external/extsensors/main.cpp | 82 ++++++++++++++++ .../external/extsensors/ui_extsensors.cpp | 86 +++++++++++++++++ .../external/extsensors/ui_extsensors.hpp | 96 +++++++++++++++++++ firmware/application/usb_serial_shell.cpp | 27 +++++- firmware/common/message.hpp | 27 +++++- firmware/common/spi_image.hpp | 1 + 8 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 firmware/application/external/extsensors/main.cpp create mode 100644 firmware/application/external/extsensors/ui_extsensors.cpp create mode 100644 firmware/application/external/extsensors/ui_extsensors.hpp diff --git a/firmware/application/external/external.cmake b/firmware/application/external/external.cmake index c4fc0c4c5..b37b0f081 100644 --- a/firmware/application/external/external.cmake +++ b/firmware/application/external/external.cmake @@ -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 ) diff --git a/firmware/application/external/external.ld b/firmware/application/external/external.ld index 26fda9379..3249ea45c 100644 --- a/firmware/application/external/external.ld +++ b/firmware/application/external/external.ld @@ -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 + + + } diff --git a/firmware/application/external/extsensors/main.cpp b/firmware/application/external/extsensors/main.cpp new file mode 100644 index 000000000..279264093 --- /dev/null +++ b/firmware/application/external/extsensors/main.cpp @@ -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(); +} +} // 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 +}; +} diff --git a/firmware/application/external/extsensors/ui_extsensors.cpp b/firmware/application/external/extsensors/ui_extsensors.cpp new file mode 100644 index 000000000..572effe65 --- /dev/null +++ b/firmware/application/external/extsensors/ui_extsensors.cpp @@ -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 \ No newline at end of file diff --git a/firmware/application/external/extsensors/ui_extsensors.hpp b/firmware/application/external/extsensors/ui_extsensors.hpp new file mode 100644 index 000000000..e068ff6d2 --- /dev/null +++ b/firmware/application/external/extsensors/ui_extsensors.hpp @@ -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(p); + this->on_gps(message); + }}; + MessageHandlerRegistration message_handler_orientation{ + Message::ID::OrientationData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_orientation(message); + }}; + + MessageHandlerRegistration message_handler_environment{ + Message::ID::EnvironmentData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_environment(message); + }}; +}; +}; // namespace ui::external_app::extsensors + +#endif /*__UI_EXTSENSORS_H__*/ diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 0f952f751..e00b7f4b1 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -922,13 +922,33 @@ static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) { } static void cmd_gotorientation(BaseSequentialStream* chp, int argc, char* argv[]) { - const char* usage = "usage: gotorientation \r\n"; - if (argc != 1) { + const char* usage = "usage: gotorientation [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 [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"); } @@ -1055,6 +1075,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}, diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index aae2239a8..54f5d9b53 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -120,6 +120,7 @@ class Message { SubGhzDData = 62, GPSPosData = 63, OrientationData = 64, + EnvironmentData = 65, MAX }; @@ -1328,11 +1329,33 @@ class GPSPosDataMessage : public Message { 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__*/ diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 27b6fda5c..9ee84fb65 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -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'}; From 1fbfdbccf8ffea47b8a57e6d801365d7de7295bb Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:29:13 -0600 Subject: [PATCH 23/98] Remove unused text_info widget (#1955) --- firmware/application/ui_navigation.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index c405c2241..7facbe7c7 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -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}, ""}; From b5e66387c37f5973d0facdec1dd51663e0539c59 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:26:56 +0100 Subject: [PATCH 24/98] 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 --- firmware/application/apps/ui_level.cpp | 24 +++++++++++++++++----- firmware/application/apps/ui_level.hpp | 10 ++++++--- firmware/application/ui/ui_rssi.cpp | 16 +++++++-------- firmware/application/ui/ui_rssi.hpp | 24 +++++++++++----------- firmware/application/ui_navigation.cpp | 3 ++- firmware/baseband/rssi_stats_collector.hpp | 6 +++--- firmware/common/message.hpp | 8 ++++---- 7 files changed, 55 insertions(+), 36 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 27c1b2f6a..4fb7aa9e1 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -39,6 +39,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 +60,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 +145,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); @@ -154,12 +162,18 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { last_max_db = statistics.max_db; freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db"); } + // 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) + "%"); + } // refresh rssi if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) { last_min_rssi = rssi_graph.get_graph_min(); last_avg_rssi = rssi_graph.get_graph_avg(); last_max_rssi = rssi_graph.get_graph_max(); - freq_stats_rssi.set("RSSI: " + to_string_dec_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())); } } /* on_statistic_updates */ diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index f1d105225..15f7f7b86 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -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{ @@ -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,9 +148,14 @@ class LevelView : public View { {"240x", 240}, }}; + // RxSat: XX% + Text freq_stats_rx{ + {0 * 8, 5 * 16 + 4, 10 * 8, 14}, + }; + 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{ diff --git a/firmware/application/ui/ui_rssi.cpp b/firmware/application/ui/ui_rssi.cpp index be95d8ba6..41e0a783e 100644 --- a/firmware/application/ui/ui_rssi.cpp +++ b/firmware/application/ui/ui_rssi.cpp @@ -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_; } diff --git a/firmware/application/ui/ui_rssi.hpp b/firmware/application/ui/ui_rssi.hpp index 7026edfc6..7af30a3ce 100644 --- a/firmware/application/ui/ui_rssi.hpp +++ b/firmware/application/ui/ui_rssi.hpp @@ -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; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 012c0948a..6da3c71f1 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -861,6 +861,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 +880,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; } diff --git a/firmware/baseband/rssi_stats_collector.hpp b/firmware/baseband/rssi_stats_collector.hpp index f1aa5df55..eae61567c 100644 --- a/firmware/baseband/rssi_stats_collector.hpp +++ b/firmware/baseband/rssi_stats_collector.hpp @@ -22,12 +22,12 @@ #ifndef __RSSI_STATS_COLLECTOR_H__ #define __RSSI_STATS_COLLECTOR_H__ -#include "rssi.hpp" -#include "message.hpp" - #include #include +#include "rssi.hpp" +#include "message.hpp" + class RSSIStatisticsCollector { public: template diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 54f5d9b53..4873ee835 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -133,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 { From d895c9fa915cfc7207c9cb44565735a33b70c021 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:39:06 -0600 Subject: [PATCH 25/98] Show true M0 free heap space in DFU overlay (#1961) --- firmware/application/apps/ui_dfu_menu.cpp | 24 ++++++++++++++--------- firmware/application/apps/ui_dfu_menu.hpp | 20 +++++++++++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/firmware/application/apps/ui_dfu_menu.cpp b/firmware/application/apps/ui_dfu_menu.cpp index f816ec47d..63efe41ff 100644 --- a/firmware/application/apps/ui_dfu_menu.cpp +++ b/firmware/application/apps/ui_dfu_menu.cpp @@ -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}, diff --git a/firmware/application/apps/ui_dfu_menu.hpp b/firmware/application/apps/ui_dfu_menu.hpp index 1cdd8adf0..9729bcb71 100644 --- a/firmware/application/apps/ui_dfu_menu.hpp +++ b/firmware/application/apps/ui_dfu_menu.hpp @@ -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 { From 73c29f666f2e03c4461483bcde643213ad93aa41 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:03:07 -0600 Subject: [PATCH 26/98] Commented out Debug -> Memory Usage app (#1962) --- firmware/application/apps/ui_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index 1cb70410f..50cd93f0c 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -479,7 +479,7 @@ DebugMenuView::DebugMenuView(NavigationView& nav) { {"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(); }}, - {"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, + //{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, {"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push(); }}, {"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, //{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, From 9d8132978f0f84579acfa3b555856d5c00913bc6 Mon Sep 17 00:00:00 2001 From: Brumi-2021 <86470699+Brumi-2021@users.noreply.github.com> Date: Sat, 9 Mar 2024 23:46:38 +0100 Subject: [PATCH 27/98] Adding Rx IQ error phase CAL to SPEC Audio_App (#1963) --- .../application/apps/analog_audio_app.cpp | 34 ++++++++++++++++--- .../application/apps/analog_audio_app.hpp | 29 ++++++++++++++-- firmware/application/hw/max2837.cpp | 33 ++++++++++++++++-- firmware/application/hw/max2837.hpp | 2 +- firmware/application/hw/max2839.cpp | 29 ++++++++++++++-- firmware/application/hw/max2839.hpp | 8 ++--- firmware/application/hw/max283x.hpp | 2 +- firmware/application/radio.cpp | 4 +++ firmware/application/radio.hpp | 1 + 9 files changed, 125 insertions(+), 17 deletions(-) diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 185b79e5c..8cd816d1b 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -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, + hackrf_r9 ? &field_rx_iq_phase_cal_2839 : &field_rx_iq_phase_cal_2837 // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31] + }); 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,18 @@ SPECOptionsView::SPECOptionsView( field_speed.on_change = [this, view](int32_t v) { view->set_spec_trigger(v); }; + + if (hackrf_r9) { // MAX2839 has 6 bits RX IQ CAL phasse adjustment. + field_rx_iq_phase_cal_2839.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_2839.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 + }; + } else { // MAX2837 has 5 bits RX IQ CAL phase adjustment. + field_rx_iq_phase_cal_2837.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_2837.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 + }; + } } /* AnalogAudioView *******************************************************/ @@ -213,6 +230,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; } diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index 9d78618d7..b4b86a803 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -133,6 +133,23 @@ 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_2837{ + {28 * 8, 0 * 16}, + 2, + {0, 31}, // 5 bits IQ CAL phase adjustment. + 1, + ' ', + }; + NumberField field_rx_iq_phase_cal_2839{ + {28 * 8, 0 * 16}, + 2, + {0, 63}, // 6 bits IQ CAL phase adjustment. + 1, + ' ', + }; }; class AnalogAudioView : public View { @@ -152,14 +169,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}; diff --git a/firmware/application/hw/max2837.cpp b/firmware/application/hw/max2837.cpp index f262bec94..e550f32f4 100644 --- a/firmware/application/hw/max2837.cpp +++ b/firmware/application/hw/max2837.cpp @@ -150,7 +150,7 @@ 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) */ + /* 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 . @@ -324,14 +324,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; diff --git a/firmware/application/hw/max2837.hpp b/firmware/application/hw/max2837.hpp index 96eb2709f..fb8fcc518 100644 --- a/firmware/application/hw/max2837.hpp +++ b/firmware/application/hw/max2837.hpp @@ -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); diff --git a/firmware/application/hw/max2839.cpp b/firmware/application/hw/max2839.cpp index bc50b1186..02f89a3f3 100644 --- a/firmware/application/hw/max2839.cpp +++ b/firmware/application/hw/max2839.cpp @@ -367,13 +367,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) { diff --git a/firmware/application/hw/max2839.hpp b/firmware/application/hw/max2839.hpp index fba590fdf..98adcc02a 100644 --- a/firmware/application/hw/max2839.hpp +++ b/firmware/application/hw/max2839.hpp @@ -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; diff --git a/firmware/application/hw/max283x.hpp b/firmware/application/hw/max283x.hpp index b25de3f8c..25656a76f 100644 --- a/firmware/application/hw/max283x.hpp +++ b/firmware/application/hw/max283x.hpp @@ -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); diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 23b5fa44d..1e00c5cdb 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -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); } diff --git a/firmware/application/radio.hpp b/firmware/application/radio.hpp index 293b93637..560653497 100644 --- a/firmware/application/radio.hpp +++ b/firmware/application/radio.hpp @@ -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); From e496f8ecc27c3794264ff9b997837c3e3d121ab5 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:36:48 -0600 Subject: [PATCH 28/98] Eliminate unnecessary NumberField to save code space (#1964) * Eliminate extra NumberField to save code space * Clang --- .../application/apps/analog_audio_app.cpp | 18 ++++++---------- .../application/apps/analog_audio_app.hpp | 11 ++-------- firmware/application/apps/ui_mictx.cpp | 21 +++++++------------ firmware/application/apps/ui_mictx.hpp | 12 ++--------- 4 files changed, 17 insertions(+), 45 deletions(-) diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 8cd816d1b..78fc28b30 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -119,7 +119,7 @@ SPECOptionsView::SPECOptionsView( &text_speed, &field_speed, &text_rx_cal, - hackrf_r9 ? &field_rx_iq_phase_cal_2839 : &field_rx_iq_phase_cal_2837 // max2839 has 6 bits [0..63], max2837 has 5 bits [0..31] + &field_rx_iq_phase_cal, }); options_config.set_selected_index(view->get_spec_bw_index()); @@ -132,17 +132,11 @@ SPECOptionsView::SPECOptionsView( view->set_spec_trigger(v); }; - if (hackrf_r9) { // MAX2839 has 6 bits RX IQ CAL phasse adjustment. - field_rx_iq_phase_cal_2839.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_2839.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 - }; - } else { // MAX2837 has 5 bits RX IQ CAL phase adjustment. - field_rx_iq_phase_cal_2837.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_2837.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 - }; - } + 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 + }; } /* AnalogAudioView *******************************************************/ diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index b4b86a803..56da85404 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -136,17 +136,10 @@ class SPECOptionsView : public View { 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_2837{ + NumberField field_rx_iq_phase_cal{ {28 * 8, 0 * 16}, 2, - {0, 31}, // 5 bits IQ CAL phase adjustment. - 1, - ' ', - }; - NumberField field_rx_iq_phase_cal_2839{ - {28 * 8, 0 * 16}, - 2, - {0, 63}, // 6 bits IQ CAL phase adjustment. + {0, 63}, // 5 or 6 bits IQ CAL phase adjustment (range updated later) 1, ' ', }; diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 60870e959..c7b47c35a 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -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; diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 7dffed175..8a0c18c86 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -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, ' ', }; From 160a7781042441f6abc593f8b3cd2ca681c6c629 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 10 Mar 2024 01:45:54 +0100 Subject: [PATCH 29/98] 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 --- firmware/application/apps/ui_recon.cpp | 59 ++++++++++++------- firmware/application/apps/ui_recon.hpp | 3 + .../application/apps/ui_recon_settings.cpp | 4 ++ .../application/apps/ui_recon_settings.hpp | 21 +++++-- .../common/portapack_persistent_memory.cpp | 8 ++- .../common/portapack_persistent_memory.hpp | 2 + 6 files changed, 68 insertions(+), 29 deletions(-) diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 16077267c..03f2c8b02 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -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(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(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(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(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(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 diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index 3a0c212a3..d9943f926 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -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, diff --git a/firmware/application/apps/ui_recon_settings.cpp b/firmware/application/apps/ui_recon_settings.cpp index 88ce0d040..543476af4 100644 --- a/firmware/application/apps/ui_recon_settings.cpp +++ b/firmware/application/apps/ui_recon_settings.cpp @@ -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()); diff --git a/firmware/application/apps/ui_recon_settings.hpp b/firmware/application/apps/ui_recon_settings.hpp index 8e2477ac1..fee03164b 100644 --- a/firmware/application/apps/ui_recon_settings.hpp +++ b/firmware/application/apps/ui_recon_settings.hpp @@ -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, diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index c7d74705e..db8808a63 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -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); @@ -832,7 +833,9 @@ bool recon_repeat_amp() { bool recon_load_repeaters() { return (data->recon_config & 0x00080000UL) ? true : false; } - +bool recon_repeat_recorded_file_mode() { + return (data->recon_config & 0x00040000UL) ? true : false; +} void set_recon_autosave_freqs(const bool v) { data->recon_config = (data->recon_config & ~0x80000000UL) | (v << 31); } @@ -881,6 +884,9 @@ void set_recon_repeat_amp(const bool v) { void set_recon_load_repeaters(const bool v) { data->recon_config = (data->recon_config & ~0x00080000UL) | (v << 19); } +void set_recon_repeat_recorded_file_mode(const bool v) { + data->recon_config = (data->recon_config & ~0x00040000UL) | (v << 18); +} /* UI Config 2 */ bool ui_hide_speaker() { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 7a857e865..6c40fa3a6 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -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); From 3b79549129017f73ce24ed28f112d6968a81c301 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 10 Mar 2024 01:30:05 -0600 Subject: [PATCH 30/98] Added enums for recon_config bits (#1965) --- .../common/portapack_persistent_memory.cpp | 81 ++++++++++++------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index db8808a63..b904722be 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -785,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; @@ -828,46 +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 (data->recon_config & 0x00040000UL) ? true : false; + 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; @@ -879,13 +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) { - data->recon_config = (data->recon_config & ~0x00040000UL) | (v << 18); + set_recon_config_bit(RC_REPEAT_FILE_MODE, v); } /* UI Config 2 */ From 2ac36d2d0ba75398ddf7d56d732169b7b434a632 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 10 Mar 2024 18:29:21 +0100 Subject: [PATCH 31/98] Level app: coloration of RxSat value (#1969) --- firmware/application/apps/ui_level.cpp | 28 ++++++++++++++++++++------ firmware/application/apps/ui_level.hpp | 8 ++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 4fb7aa9e1..3cdf739aa 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -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; @@ -162,12 +163,6 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { last_max_db = statistics.max_db; freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db"); } - // 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) + "%"); - } // refresh rssi if (last_min_rssi != rssi_graph.get_graph_min() || last_avg_rssi != rssi_graph.get_graph_avg() || last_max_rssi != rssi_graph.get_graph_max()) { last_min_rssi = rssi_graph.get_graph_min(); @@ -175,6 +170,27 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { last_max_rssi = rssi_graph.get_graph_max(); freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi) + ", 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; + 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) { diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 15f7f7b86..0f9681e84 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -116,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{ @@ -150,7 +150,7 @@ class LevelView : public View { // RxSat: XX% Text freq_stats_rx{ - {0 * 8, 5 * 16 + 4, 10 * 8, 14}, + {0 * 8, 5 * 16 + 4, 10 * 8, 1 * 16}, }; RSSIGraph rssi_graph{ @@ -160,7 +160,7 @@ class LevelView : public View { 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); From 986e37a3c9db1cc0f27fd5e63cdda3a32d95eac3 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 10 Mar 2024 20:05:05 +0100 Subject: [PATCH 32/98] fix unused warning (#1970) --- firmware/application/apps/ui_level.cpp | 36 ++++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 3cdf739aa..278e57620 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -172,24 +172,26 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { } // refresh sat uint8_t rx_sat = ((uint32_t)shared_memory.m4_performance_counter) * 100 / 127; - 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; + 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); } - 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 */ From e9b9ba4602c8c1904b01095d93543e887adffacf Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 10 Mar 2024 14:49:36 -0500 Subject: [PATCH 33/98] Deallocate menu buttons to save memory (#1971) * Deallocate hidden menu buttons * Added Copyright * Added comments --- firmware/application/apps/ui_debug.cpp | 56 ++++++++++++++--------- firmware/application/apps/ui_debug.hpp | 12 +++++ firmware/application/apps/ui_settings.cpp | 47 ++++++++++--------- firmware/application/apps/ui_settings.hpp | 6 ++- firmware/application/ui/ui_btngrid.cpp | 24 ++++++++-- firmware/application/ui/ui_btngrid.hpp | 6 +++ firmware/application/ui_navigation.cpp | 50 ++++++++++++-------- firmware/application/ui_navigation.hpp | 14 ++++++ 8 files changed, 149 insertions(+), 66 deletions(-) diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index 50cd93f0c..3f533e460 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -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("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }}, - {max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, max283x]() { nav.push(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }}, - {si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav, si5351x]() { nav.push(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }}, - {audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [&nav]() { nav.push(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("RFFC5072", RegistersWidgetConfig{CT_RFFC5072, 31, 31, 16}); }}, + {max283x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this, max283x]() { nav_.push(max283x, RegistersWidgetConfig{CT_MAX283X, 32, 32, 10}); }}, + {si5351x, ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this, si5351x]() { nav_.push(si5351x, RegistersWidgetConfig{CT_SI5351, 188, 96, 8}); }}, + {audio::debug::codec_name(), ui::Color::dark_cyan(), &bitmap_icon_peripherals_details, [this]() { nav_.push(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(); }}, - {"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(); }}, - //{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, - {"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push(); }}, - {"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, - //{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push(); } }, - {"Reboot", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push(); }}, - {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push(); }}, - {"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push(); }}, - {"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push(); }}, + {"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [this]() { nav_.push(); }}, + {"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(); }}, + //{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push(); }}, + {"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [this]() { nav_.push(); }}, + {"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push(); }}, + //{ "Radio State", ui::Color::white(), nullptr, [this](){ nav_.push(); } }, + {"Reboot", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, + {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push(); }}, + {"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [this]() { nav_.push(); }}, + {"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [this]() { nav_.push(); }}, }); - 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 *********************************************************/ diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp index 571e2bfd2..9665389be 100644 --- a/firmware/application/apps/ui_debug.hpp +++ b/firmware/application/apps/ui_debug.hpp @@ -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 */ diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 24d15adc6..a4479fe81 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -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(); }}, - {"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav]() { nav.push(); }}, - {"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push(); }}, - {"Config Mode", ui::Color::dark_cyan(), &bitmap_icon_clk_ext, [&nav]() { nav.push(); }}, - {"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, - {"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [&nav]() { nav.push(); }}, - {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push(); }}, - {"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, - {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, - {"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, - {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push(); }}, - {"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav]() { nav.push(); }}, - {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push(); }}, - {"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push(); }}, - {"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push(); }}, - }); +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(); }}, + {"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [this]() { nav_.push(); }}, + {"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [this]() { nav_.push(); }}, + {"Config Mode", ui::Color::dark_cyan(), &bitmap_icon_clk_ext, [this]() { nav_.push(); }}, + {"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, + {"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [this]() { nav_.push(); }}, + {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, + {"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, + {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push(); }}, + {"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, + {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push(); }}, + {"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push(); }}, + {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push(); }}, + {"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, + {"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, + }); +} + } /* namespace ui */ diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 83ef294d0..77fc3a784 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -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 */ diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index 92891e852..ec7cd1934 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -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,12 @@ void BtnGridView::on_tick_second() { } void BtnGridView::clear() { - menu_items.clear(); + std::vector().swap(menu_items); // clear vector and release memory + + for (auto& item : menu_item_views) + remove_child(item.get()); + + std::vector>().swap(menu_item_views); // clear vector and release memory } void BtnGridView::add_items(std::initializer_list new_items) { @@ -207,11 +213,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: diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp index 03ba22dfd..2256f7665 100644 --- a/firmware/application/ui/ui_btngrid.hpp +++ b/firmware/application/ui/ui_btngrid.hpp @@ -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(); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 6da3c71f1..d417002d7 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -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( diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 7facbe7c7..05576663e 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -329,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 { @@ -348,6 +360,8 @@ class SystemMenuView : public BtnGridView { SystemMenuView(NavigationView& nav); private: + NavigationView& nav_; + void on_populate() override; void hackrf_mode(NavigationView& nav); }; From ccd71d9593b91e96d517ee05d789e8785752d775 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sun, 10 Mar 2024 14:50:48 -0500 Subject: [PATCH 34/98] Set iq_phase_cal in radio when starting SPEC mode (#1972) --- firmware/application/apps/analog_audio_app.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 78fc28b30..2be1ccd4f 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -137,6 +137,8 @@ SPECOptionsView::SPECOptionsView( 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 *******************************************************/ From 866e12fbc5761830cbb6ee4bc14ccc825c08eae9 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 10 Mar 2024 23:25:18 +0100 Subject: [PATCH 35/98] added RXIQCALC (#1974) Co-authored-by: GullCode --- .../application/apps/ui_looking_glass_app.cpp | 17 +++++++++++++++++ .../application/apps/ui_looking_glass_app.hpp | 19 ++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 8371b8958..62a2b03a6 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -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"); diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index 21d4f5203..d3052c6fe 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -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, From 910fd820514492f1be106b5e03f0d76a80820fd3 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:40:47 +0100 Subject: [PATCH 36/98] 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 --- firmware/application/apps/ui_freqman.cpp | 2 +- firmware/application/apps/ui_freqman.hpp | 8 +++----- firmware/application/freqman_db.cpp | 4 ++-- firmware/application/freqman_db.hpp | 3 +++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 47f971c0e..50a44f64b 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -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); diff --git a/firmware/application/apps/ui_freqman.hpp b/firmware/application/apps/ui_freqman.hpp index 0ece16a37..52ecc864b 100644 --- a/firmware/application/apps/ui_freqman.hpp +++ b/firmware/application/apps/ui_freqman.hpp @@ -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{ diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index 6bbc3d776..e676d3b9b 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -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; } } diff --git a/firmware/application/freqman_db.hpp b/firmware/application/freqman_db.hpp index 4f31ea043..6e1a1d7b7 100644 --- a/firmware/application/freqman_db.hpp +++ b/firmware/application/freqman_db.hpp @@ -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}; From 3c489e1a81f1cabe509e9b12af386d79783c98b2 Mon Sep 17 00:00:00 2001 From: Erwin Ried <1091420+eried@users.noreply.github.com> Date: Wed, 13 Mar 2024 12:30:05 +0100 Subject: [PATCH 37/98] Steamlining the warning (#1984) I think it is enough to note nobody should pay for the download --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6758f3394..a7fe06031 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ > [!WARNING] -> Recently, we have become aware of certain individuals distributing prepackaged packages of Mayhem for a fee, and we want to bring this to your attention to ensure the integrity and security of our project. -> -> We would like to clarify that none of the contributors to Mayhem receive any monetary compensation for their efforts. All the work put into this project is driven by passion and hobby, and we are committed to providing the community with an open-source solution that remains free of charge. -> -> __IF YOU'VE PAID FOR MAYHEM OR ANY PREPACKAGED PACKAGES, YOU'RE BEING SCAMMED.__ Seek a refund from your card company and report the issue immediately. -> The only legitimate link leading to our repositories is the organization [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware). Please ensure that any download or access to our software is done exclusively through these trusted sources. +> __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 From 0b2d5f75ccd480aaf8ba740f0244904cbc828e9e Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:07:44 -0500 Subject: [PATCH 38/98] 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 --- firmware/baseband/audio_dma.cpp | 42 +++++++++++-------- firmware/baseband/audio_dma.hpp | 5 +-- firmware/baseband/baseband.cpp | 8 +--- .../baseband/{main.cpp => main.cpp.unused} | 0 firmware/baseband/proc_afskrx.cpp | 4 ++ firmware/baseband/proc_am_audio.cpp | 3 ++ firmware/baseband/proc_aprsrx.cpp | 4 ++ firmware/baseband/proc_audiotx.cpp | 3 ++ firmware/baseband/proc_mictx.cpp | 3 ++ firmware/baseband/proc_nfm_audio.cpp | 4 ++ firmware/baseband/proc_pocsag.cpp | 3 ++ firmware/baseband/proc_pocsag2.cpp | 3 ++ firmware/baseband/proc_sonde.cpp | 3 ++ firmware/baseband/proc_tones.cpp | 3 ++ firmware/baseband/proc_wfm_audio.cpp | 3 ++ firmware/baseband/proc_wideband_spectrum.cpp | 3 ++ 16 files changed, 67 insertions(+), 27 deletions(-) rename firmware/baseband/{main.cpp => main.cpp.unused} (100%) diff --git a/firmware/baseband/audio_dma.cpp b/firmware/baseband/audio_dma.cpp index f493fd939..356faea3b 100644 --- a/firmware/baseband/audio_dma.cpp +++ b/firmware/baseband/audio_dma.cpp @@ -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(&LPC_I2S0->TXFIFO); const auto control_value = control_tx(transfer_bytes); @@ -194,22 +186,34 @@ 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(); + nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY)); +} + +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(); + nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY)); +} + void disable() { gpdma_channel_i2s0_tx.disable(); gpdma_channel_i2s0_rx.disable(); @@ -217,6 +221,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 diff --git a/firmware/baseband/audio_dma.hpp b/firmware/baseband/audio_dma.hpp index 8634de820..41573524f 100644 --- a/firmware/baseband/audio_dma.hpp +++ b/firmware/baseband/audio_dma.hpp @@ -43,9 +43,8 @@ using buffer_t = buffer_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); diff --git a/firmware/baseband/baseband.cpp b/firmware/baseband/baseband.cpp index 5de5ec464..aac665fd0 100644 --- a/firmware/baseband/baseband.cpp +++ b/firmware/baseband/baseband.cpp @@ -28,14 +28,8 @@ #include "gpdma.hpp" -#include "audio_dma.hpp" - static void init() { - audio::dma::init(); - audio::dma::configure(); - audio::dma::enable(); - - nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY)); + // Audio DMA initialization was moved to baseband proc's that actually use DMA audio, to save memory. } static void halt() { diff --git a/firmware/baseband/main.cpp b/firmware/baseband/main.cpp.unused similarity index 100% rename from firmware/baseband/main.cpp rename to firmware/baseband/main.cpp.unused diff --git a/firmware/baseband/proc_afskrx.cpp b/firmware/baseband/proc_afskrx.cpp index 27b1b4616..804518ece 100644 --- a/firmware/baseband/proc_afskrx.cpp +++ b/firmware/baseband/proc_afskrx.cpp @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_am_audio.cpp b/firmware/baseband/proc_am_audio.cpp index 160356303..a1304c464 100644 --- a/firmware/baseband/proc_am_audio.cpp +++ b/firmware/baseband/proc_am_audio.cpp @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_aprsrx.cpp b/firmware/baseband/proc_aprsrx.cpp index 616bbb417..60b048b02 100644 --- a/firmware/baseband/proc_aprsrx.cpp +++ b/firmware/baseband/proc_aprsrx.cpp @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_audiotx.cpp b/firmware/baseband/proc_audiotx.cpp index d7991ccec..b8d70660a 100644 --- a/firmware/baseband/proc_audiotx.cpp +++ b/firmware/baseband/proc_audiotx.cpp @@ -24,6 +24,7 @@ #include "portapack_shared_memory.hpp" #include "sine_table_int8.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index be37c9c9f..9f0d37718 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -25,6 +25,7 @@ #include "sine_table_int8.hpp" #include "tonesets.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_nfm_audio.cpp b/firmware/baseband/proc_nfm_audio.cpp index 6b4e61352..47e1f7d41 100644 --- a/firmware/baseband/proc_nfm_audio.cpp +++ b/firmware/baseband/proc_nfm_audio.cpp @@ -24,6 +24,8 @@ #include "sine_table_int8.hpp" #include "portapack_shared_memory.hpp" +#include "audio_dma.hpp" + #include "event_m4.hpp" #include @@ -174,6 +176,8 @@ void NarrowbandFMAudio::capture_config(const CaptureConfigMessage& message) { } int main() { + audio::dma::init_audio_out(); + EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_pocsag.cpp b/firmware/baseband/proc_pocsag.cpp index 0101b7485..b05abd495 100644 --- a/firmware/baseband/proc_pocsag.cpp +++ b/firmware/baseband/proc_pocsag.cpp @@ -27,6 +27,7 @@ #include "dsp_iir_config.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include #include @@ -530,6 +531,8 @@ uint32_t POCSAGProcessor::getRate() const { // // ==================================================================== int main() { + audio::dma::init_audio_out(); + EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_pocsag2.cpp b/firmware/baseband/proc_pocsag2.cpp index 15c157389..1170a520b 100644 --- a/firmware/baseband/proc_pocsag2.cpp +++ b/firmware/baseband/proc_pocsag2.cpp @@ -26,6 +26,7 @@ #include "proc_pocsag2.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include #include @@ -416,6 +417,8 @@ void POCSAGProcessor::send_packet() { /* main **************************************************/ int main() { + audio::dma::init_audio_out(); + EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index 1477c3573..7c145ed3b 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -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()}; event_dispatcher.run(); diff --git a/firmware/baseband/proc_tones.cpp b/firmware/baseband/proc_tones.cpp index 1af4bc473..f59c554b1 100644 --- a/firmware/baseband/proc_tones.cpp +++ b/firmware/baseband/proc_tones.cpp @@ -23,6 +23,7 @@ #include "proc_tones.hpp" #include "sine_table_int8.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include @@ -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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_wfm_audio.cpp b/firmware/baseband/proc_wfm_audio.cpp index f6a3cb39d..7a59c73fa 100644 --- a/firmware/baseband/proc_wfm_audio.cpp +++ b/firmware/baseband/proc_wfm_audio.cpp @@ -26,6 +26,7 @@ #include "audio_output.hpp" #include "dsp_fft.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include @@ -188,6 +189,8 @@ void WidebandFMAudio::capture_config(const CaptureConfigMessage& message) { } int main() { + audio::dma::init_audio_out(); + EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_wideband_spectrum.cpp b/firmware/baseband/proc_wideband_spectrum.cpp index a7377b0b8..35aef2ee6 100644 --- a/firmware/baseband/proc_wideband_spectrum.cpp +++ b/firmware/baseband/proc_wideband_spectrum.cpp @@ -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()}; event_dispatcher.run(); return 0; From 61dc8a0225d68a71f81816958dfa29c417b4616c Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:08:52 -0500 Subject: [PATCH 39/98] Disabled unused baseband "no-op" process (#1986) --- .../application/external/calculator/main.cpp | 4 ++-- .../application/external/font_viewer/main.cpp | 2 +- firmware/application/external/pacman/main.cpp | 4 ++-- firmware/application/external/tetris/main.cpp | 4 ++-- firmware/baseband/CMakeLists.txt | 20 +++++++++---------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/firmware/application/external/calculator/main.cpp b/firmware/application/external/calculator/main.cpp index 0a9ce0c33..e03488b64 100644 --- a/firmware/application/external/calculator/main.cpp +++ b/firmware/application/external/calculator/main.cpp @@ -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 }; } diff --git a/firmware/application/external/font_viewer/main.cpp b/firmware/application/external/font_viewer/main.cpp index f83e7be84..be07615cd 100644 --- a/firmware/application/external/font_viewer/main.cpp +++ b/firmware/application/external/font_viewer/main.cpp @@ -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 }; } diff --git a/firmware/application/external/pacman/main.cpp b/firmware/application/external/pacman/main.cpp index 9d2d4f50f..657172604 100644 --- a/firmware/application/external/pacman/main.cpp +++ b/firmware/application/external/pacman/main.cpp @@ -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 }; } diff --git a/firmware/application/external/tetris/main.cpp b/firmware/application/external/tetris/main.cpp index 6a2134c51..f34a020fe 100644 --- a/firmware/application/external/tetris/main.cpp +++ b/firmware/application/external/tetris/main.cpp @@ -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 }; } diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 8357c6cb0..99f4dca39 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -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 From 999f9e2ded8d2a07c322e4792669c2d2177a288e Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:57:35 -0500 Subject: [PATCH 40/98] Fix #1982 (enable DMA interrupt for all apps) (#1987) --- firmware/baseband/audio_dma.cpp | 2 -- firmware/baseband/baseband.cpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/firmware/baseband/audio_dma.cpp b/firmware/baseband/audio_dma.cpp index 356faea3b..f8e843b08 100644 --- a/firmware/baseband/audio_dma.cpp +++ b/firmware/baseband/audio_dma.cpp @@ -203,7 +203,6 @@ void init_audio_out() { // LPC_GPDMA->SYNC |= (1 << gpdma_tx_peripheral); configure_tx(); enable_tx(); - nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY)); } void init_audio_in() { @@ -211,7 +210,6 @@ void init_audio_in() { // LPC_GPDMA->SYNC |= (1 << gpdma_rx_peripheral); configure_rx(); enable_rx(); - nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY)); } void disable() { diff --git a/firmware/baseband/baseband.cpp b/firmware/baseband/baseband.cpp index aac665fd0..02c14b7d5 100644 --- a/firmware/baseband/baseband.cpp +++ b/firmware/baseband/baseband.cpp @@ -30,6 +30,7 @@ static void init() { // 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)); } static void halt() { From 14f42d1fe84f239be005547e5cdbe032cb2455cc Mon Sep 17 00:00:00 2001 From: not tre mann <24917424+zxkmm@users.noreply.github.com> Date: Thu, 14 Mar 2024 01:06:14 +0800 Subject: [PATCH 41/98] support "clean" files (#1983) * init for clean files * textual * icons position --- firmware/application/apps/ui_fileman.cpp | 54 +++++++++++++++++++++++- firmware/application/apps/ui_fileman.hpp | 17 ++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index cb3598780..a4b007fec 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -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", "Directory not empty;\nUse \"clean\" button\nto clean it first"); return; } @@ -474,6 +475,51 @@ void FileManagerView::on_delete() { }); } +void FileManagerView::on_clean() { + if (is_directory(get_selected_full_path()) && !is_empty_directory(get_selected_full_path())) { + ////selected a dir, who is not empty, del sub files + nav_.push( + "Delete", "Will delete all sub files\nexclude sub-folders,\nin this folder\nAre you sure?", YESNO, + [this](bool choice) { + if (choice) { + std::vector file_list; + file_list = scan_root_files(get_selected_full_path(), u"*"); + + for (const auto& file_name : file_list) { + std::filesystem::path current_full_path = get_selected_full_path() / file_name; + delete_file(current_full_path); + } + reload_current(); + } + }); + } else if (!is_directory(get_selected_full_path()) && !is_empty_directory(get_selected_full_path())) { + ////selected a file, will del it and all others in this dir + nav_.push( + "Delete", "Will delete all files\nexclude sub-folders\nin this folder,\nAre you sure?", YESNO, + [this](bool choice) { + if (choice) { + std::vector file_list; + file_list = scan_root_files(get_selected_full_path().parent_path(), u"*"); + + for (const auto& file_name : file_list) { + std::filesystem::path current_full_path = get_selected_full_path().parent_path() / file_name; + delete_file(current_full_path); + } + reload_current(); + } + }); + + } else if (is_directory(get_selected_full_path()) && is_empty_directory(get_selected_full_path())) { + ////sel an empty dir, threw + nav_.display_modal("Forbid", "You selected an empty dir;\nUse delete button \ninstead of clean button\nto delete it"); + return; + } else { + ////edge case e.g. probably . or .. (maybe not needed?) + nav_.display_modal("Forbid", "Not able to do that"); + return; + } +} + void FileManagerView::on_new_dir() { name_buffer = ""; text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) { @@ -560,6 +606,7 @@ FileManagerView::FileManagerView( &text_date, &button_rename, &button_delete, + &button_clean, &button_cut, &button_copy, &button_paste, @@ -606,6 +653,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(); diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 24a145eb9..38017c786 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -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_scanner, + 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()}; From f0614c882b9b47d5d4aeaef18bc0b944c4df99fb Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:42:40 -0500 Subject: [PATCH 42/98] File manager "Clean" button tweaks (#1990) * File Manager "clean" button tweaks * Add files via upload --- firmware/application/apps/ui_fileman.cpp | 62 ++++++++--------------- firmware/application/apps/ui_fileman.hpp | 2 +- firmware/application/bitmap.hpp | 38 ++++++++++++++ firmware/graphics/icon_clean.png | Bin 0 -> 182 bytes 4 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 firmware/graphics/icon_clean.png diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index a4b007fec..9d33be043 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -450,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;\nUse \"clean\" button\nto clean it first"); + nav_.display_modal("Delete", " Folder is not empty;\n Use \"Clean\" button to\n empty it first."); return; } @@ -476,48 +476,28 @@ void FileManagerView::on_delete() { } void FileManagerView::on_clean() { - if (is_directory(get_selected_full_path()) && !is_empty_directory(get_selected_full_path())) { - ////selected a dir, who is not empty, del sub files - nav_.push( - "Delete", "Will delete all sub files\nexclude sub-folders,\nin this folder\nAre you sure?", YESNO, - [this](bool choice) { - if (choice) { - std::vector file_list; - file_list = scan_root_files(get_selected_full_path(), u"*"); - - for (const auto& file_name : file_list) { - std::filesystem::path current_full_path = get_selected_full_path() / file_name; - delete_file(current_full_path); - } - reload_current(); - } - }); - } else if (!is_directory(get_selected_full_path()) && !is_empty_directory(get_selected_full_path())) { - ////selected a file, will del it and all others in this dir - nav_.push( - "Delete", "Will delete all files\nexclude sub-folders\nin this folder,\nAre you sure?", YESNO, - [this](bool choice) { - if (choice) { - std::vector file_list; - file_list = scan_root_files(get_selected_full_path().parent_path(), u"*"); - - for (const auto& file_name : file_list) { - std::filesystem::path current_full_path = get_selected_full_path().parent_path() / file_name; - delete_file(current_full_path); - } - reload_current(); - } - }); - - } else if (is_directory(get_selected_full_path()) && is_empty_directory(get_selected_full_path())) { - ////sel an empty dir, threw - nav_.display_modal("Forbid", "You selected an empty dir;\nUse delete button \ninstead of clean button\nto delete it"); - return; - } else { - ////edge case e.g. probably . or .. (maybe not needed?) - nav_.display_modal("Forbid", "Not able to do that"); + 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( + "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 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() { diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 38017c786..892e2176c 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -236,7 +236,7 @@ class FileManagerView : public FileManBaseView { NewButton button_clean{ {13 * 8, 34 * 8, 4 * 8, 32}, {}, - &bitmap_icon_scanner, + &bitmap_icon_clean, Color::red()}; NewButton button_cut{ diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 9e2b36337..f4b1a2c21 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -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__*/ diff --git a/firmware/graphics/icon_clean.png b/firmware/graphics/icon_clean.png new file mode 100644 index 0000000000000000000000000000000000000000..62908ff97814bcc44daa746e87669cc9db8dc223 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5M?jcysy3fAP%y*O z#WBR9cj+WYp#usW%#;28|9|==NH(`C0itr7> z%8?PQZ(eP3e3CS!JU_t1`oa0e(9E8goebv#xg3h>TSH};r^Q+Fc6`grx>)-t=MzWG bpHuuLzt!ZnX11&a+R5PQ>gTe~DWM4f60JXN literal 0 HcmV?d00001 From 181624daf115f58e62645bb43d4562ea50d056b5 Mon Sep 17 00:00:00 2001 From: not tre mann <24917424+zxkmm@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:56:55 +0800 Subject: [PATCH 43/98] lambda the flash util menu add item code (#1993) * lambda the flash util menu add code * clean up --- .../application/apps/ui_flash_utility.cpp | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/firmware/application/apps/ui_flash_utility.cpp b/firmware/application/apps/ui_flash_utility.cpp index a91a39511..27bccde0e 100644 --- a/firmware/application/apps/ui_flash_utility.cpp +++ b/firmware/application/apps/ui_flash_utility.cpp @@ -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 */ \ No newline at end of file From 9e40e38f070dcd552c8c3acc55c8539b37fabc5d Mon Sep 17 00:00:00 2001 From: Totoo Date: Fri, 15 Mar 2024 14:56:20 +0100 Subject: [PATCH 44/98] 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 --- firmware/application/file.cpp | 9 +++++ firmware/application/file.hpp | 2 ++ firmware/application/metadata_file.cpp | 41 +++++++++++++++++++++++ firmware/application/metadata_file.hpp | 4 +++ firmware/application/ui_record_view.cpp | 13 ++++++- firmware/application/ui_record_view.hpp | 12 +++++++ firmware/application/usb_serial_shell.cpp | 8 +++-- firmware/common/message.hpp | 7 ++-- 8 files changed, 90 insertions(+), 6 deletions(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 57ae0899d..0964b0dac 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -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()); diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 35632685a..ae602f48f 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -155,6 +155,8 @@ struct path { path& replace_extension(const path& replacement = path()); + path& append_filename(const string_type& str); + private: string_type _s; }; diff --git a/firmware/application/metadata_file.cpp b/firmware/application/metadata_file.cpp index 3eb345212..bc5d696ec 100644 --- a/firmware/application/metadata_file.cpp +++ b/firmware/application/metadata_file.cpp @@ -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 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 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 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); +} \ No newline at end of file diff --git a/firmware/application/metadata_file.hpp b/firmware/application/metadata_file.hpp index d3e055e4b..a9d47f01d 100644 --- a/firmware/application/metadata_file.hpp +++ b/firmware/application/metadata_file.hpp @@ -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 write_metadata_file(const std::filesystem::path& path, capture_metadata metadata); Optional read_metadata_file(const std::filesystem::path& path); +bool parse_float_meta(std::string_view str, float& out_val); #endif // __METADATA_FILE_HPP__ \ No newline at end of file diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 9aac8945e..236910447 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -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 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()) { diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 785f14281..9d94d5cff 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -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(p); this->handle_capture_thread_done(message.error); }}; + + MessageHandlerRegistration message_handler_gps{ + Message::ID::GPSPosData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_gps(message); + }}; }; } /* namespace ui */ diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index e00b7f4b1..21fc12c01 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -905,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 [altitude] [speed]\r\n"; - if (argc < 2 || argc > 4) { + const char* usage = "usage: gotgps [altitude] [speed] [satinuse]\r\n"; + if (argc < 2 || argc > 5) { chprintf(chp, usage); return; } @@ -914,9 +914,11 @@ 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"); } diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 4873ee835..717fb50b2 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -1313,17 +1313,20 @@ 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 { From 01e4ff65a21abe7cb72c031b34bd6b849ce7f3ac Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:39:34 +0100 Subject: [PATCH 45/98] fix butngrid/capture and fix contributor name (#1995) * fixing contributor name * used clear instead of swap --------- Co-authored-by: GullCode --- firmware/application/apps/ui_about_simple.cpp | 4 ++-- firmware/application/ui/ui_btngrid.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/application/apps/ui_about_simple.cpp b/firmware/application/apps/ui_about_simple.cpp index acc095e75..c691af33f 100644 --- a/firmware/application/apps/ui_about_simple.cpp +++ b/firmware/application/apps/ui_about_simple.cpp @@ -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"); diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index ec7cd1934..740276126 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -107,12 +107,14 @@ void BtnGridView::on_tick_second() { } void BtnGridView::clear() { - std::vector().swap(menu_items); // clear vector and release memory + // 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()); - std::vector>().swap(menu_item_views); // clear vector and release memory + // 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 new_items) { From 6e34343bdef8ecfedf3989ccc7d546e307a7efd4 Mon Sep 17 00:00:00 2001 From: Alexandros Andreou Date: Mon, 18 Mar 2024 10:13:10 +0200 Subject: [PATCH 46/98] added all and all-safe attack types to blespam (#2003) --- .../external/blespam/ui_blespam.cpp | 57 +++++++++++++------ .../external/blespam/ui_blespam.hpp | 10 +++- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/firmware/application/external/blespam/ui_blespam.cpp b/firmware/application/external/blespam/ui_blespam.cpp index 7131ecd2b..7b7de6f8e 100644 --- a/firmware/application/external/blespam/ui_blespam.cpp +++ b/firmware/application/external/blespam/ui_blespam.cpp @@ -509,6 +509,44 @@ 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_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_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 +555,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 diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index f1b4f93f8..73b6e86aa 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -49,7 +49,9 @@ enum ATK_TYPE { ATK_IOS, ATK_IOS_CRASH, ATK_WINDOWS, - ATK_SAMSUNG + ATK_SAMSUNG, + ATK_ALL_SAFE, + ATK_ALL }; enum PKT_TYPE { PKT_TYPE_INVALID_TYPE, @@ -124,7 +126,9 @@ class BLESpamView : public View { {"iOs", 1}, {"iOs crash", 2}, {"Windows", 3}, - {"Samsung", 4}}}; + {"Samsung", 4}, + {"All-Safe", 5}, + {"All", 6}}}; bool is_running{false}; @@ -148,6 +152,8 @@ class BLESpamView : public View { void createIosPacket(bool crash); void createSamsungPacket(); void createWindowsPacket(); + void createAnyPacket(bool safe); + void createPacket(ATK_TYPE attackType); void changePacket(bool forced); void on_tx_progress(const bool done); From 8383363e741cf9ddeb7b3187686811285430a49c Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:45:02 -0500 Subject: [PATCH 47/98] Preserve radio mode when updating iq_tx_phase_cal (#2008) --- firmware/application/hw/max2837.cpp | 10 +++++++++- firmware/application/hw/max2837.hpp | 2 ++ firmware/application/hw/max2839.cpp | 10 +++++++++- firmware/application/hw/max2839.hpp | 2 ++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/firmware/application/hw/max2837.cpp b/firmware/application/hw/max2837.cpp index e550f32f4..f937a120f 100644 --- a/firmware/application/hw/max2837.cpp +++ b/firmware/application/hw/max2837.cpp @@ -150,6 +150,8 @@ void MAX2837::init() { } void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) { + 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) @@ -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++) { diff --git a/firmware/application/hw/max2837.hpp b/firmware/application/hw/max2837.hpp index fb8fcc518..7e556d449 100644 --- a/firmware/application/hw/max2837.hpp +++ b/firmware/application/hw/max2837.hpp @@ -841,6 +841,7 @@ class MAX2837 : public MAX283x { private: spi::arbiter::Target& _target; + Mode _mode{Mode::Standby}; RegisterMap _map{initial_register_values}; DirtyRegisters _dirty{}; @@ -851,6 +852,7 @@ class MAX2837 : public MAX283x { reg_t read(const Register reg); void flush(); + Mode get_mode(); }; } // namespace max2837 diff --git a/firmware/application/hw/max2839.cpp b/firmware/application/hw/max2839.cpp index 02f89a3f3..11d5819eb 100644 --- a/firmware/application/hw/max2839.cpp +++ b/firmware/application/hw/max2839.cpp @@ -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++) { diff --git a/firmware/application/hw/max2839.hpp b/firmware/application/hw/max2839.hpp index 98adcc02a..1f36fbb9f 100644 --- a/firmware/application/hw/max2839.hpp +++ b/firmware/application/hw/max2839.hpp @@ -700,6 +700,7 @@ class MAX2839 : public MAX283x { private: spi::arbiter::Target& _target; + Mode _mode{Mode::Standby}; RegisterMap _map{initial_register_values}; DirtyRegisters _dirty{}; @@ -712,6 +713,7 @@ class MAX2839 : public MAX283x { void flush(); void configure_rx_gain(); + Mode get_mode(); }; } // namespace max2839 From c1bf2620c7cbbee615f4dd486b00645220f9e711 Mon Sep 17 00:00:00 2001 From: Totoo Date: Mon, 18 Mar 2024 21:45:45 +0100 Subject: [PATCH 48/98] Bt namespam (#2009) * Add random names --- .../external/blespam/ui_blespam.cpp | 42 ++++++++++++++++++- .../external/blespam/ui_blespam.hpp | 7 +++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/firmware/application/external/blespam/ui_blespam.cpp b/firmware/application/external/blespam/ui_blespam.cpp index 7b7de6f8e..68dc74428 100644 --- a/firmware/application/external/blespam/ui_blespam.cpp +++ b/firmware/application/external/blespam/ui_blespam.cpp @@ -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; @@ -515,6 +549,7 @@ void BLESpamView::createAnyPacket(bool safe) { ATK_IOS, ATK_WINDOWS, ATK_SAMSUNG, + ATK_NAMESPAM, ATK_IOS_CRASH}; ATK_TYPE attackType = type[rand() % (COUNT_OF(type) - (1 ? safe : 0))]; createPacket(attackType); @@ -534,6 +569,9 @@ void BLESpamView::createPacket(ATK_TYPE attackType) { case ATK_WINDOWS: createWindowsPacket(); break; + case ATK_NAMESPAM: + createNameSpamPacket(); + break; case ATK_ALL_SAFE: createAnyPacket(true); break; diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index 73b6e86aa..4010c05e1 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -50,6 +50,7 @@ enum ATK_TYPE { ATK_IOS_CRASH, ATK_WINDOWS, ATK_SAMSUNG, + ATK_NAMESPAM, ATK_ALL_SAFE, ATK_ALL }; @@ -127,8 +128,9 @@ class BLESpamView : public View { {"iOs crash", 2}, {"Windows", 3}, {"Samsung", 4}, - {"All-Safe", 5}, - {"All", 6}}}; + {"NameSpam", 5}, + {"All-Safe", 6}, + {"All", 7}}}; bool is_running{false}; @@ -152,6 +154,7 @@ 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); From c5f73cf8f4a5a4501db3a2957ceae35529c854dd Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Mon, 18 Mar 2024 23:56:23 -0500 Subject: [PATCH 49/98] Darken FileMan button colors for visibility (#2010) --- firmware/application/apps/ui_fileman.cpp | 2 +- firmware/application/apps/ui_fileman.hpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 9d33be043..35e4c5e18 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -694,7 +694,7 @@ FileManagerView::FileManagerView( button_show_hidden_files.on_select = [this]() { show_hidden_files = !show_hidden_files; - button_show_hidden_files.set_color(show_hidden_files ? Color::green() : Color::dark_grey()); + button_show_hidden_files.set_color(show_hidden_files ? Color::dark_green() : Color::dark_grey()); reload_current(); }; } diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 892e2176c..83a8cda8a 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -261,26 +261,26 @@ class FileManagerView : public FileManBaseView { {22 * 8, 29 * 8, 4 * 8, 32}, {}, &bitmap_icon_new_dir, - Color::green()}; + Color::dark_green()}; NewButton button_new_file{ {26 * 8, 29 * 8, 4 * 8, 32}, {}, &bitmap_icon_new_file, - Color::green()}; + Color::dark_green()}; NewButton button_open_notepad{ {0 * 8, 34 * 8, 4 * 8, 32}, {}, &bitmap_icon_notepad, - Color::orange()}; + Color::dark_orange()}; NewButton button_rename_timestamp{ {4 * 8, 29 * 8, 4 * 8, 32}, {}, &bitmap_icon_options_datetime, - Color::orange(), + Color::dark_blue(), /*vcenter*/ true}; NewButton button_open_iq_trim{ @@ -288,7 +288,7 @@ class FileManagerView : public FileManBaseView { {4 * 8, 34 * 8, 4 * 8, 32}, {}, &bitmap_icon_trim, - Color::orange()}; + Color::dark_orange()}; NewButton button_show_hidden_files{ {17 * 8, 34 * 8, 4 * 8, 32}, From b53c8e1f806ddfc80c706cfc5c2e1399230b57fb Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Mon, 18 Mar 2024 23:58:23 -0500 Subject: [PATCH 50/98] Stop audio DMA in baseband::shutdown() (#2011) --- firmware/baseband/baseband.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/baseband/baseband.cpp b/firmware/baseband/baseband.cpp index 02c14b7d5..63df59447 100644 --- a/firmware/baseband/baseband.cpp +++ b/firmware/baseband/baseband.cpp @@ -27,6 +27,7 @@ #include "portapack_dma.hpp" #include "gpdma.hpp" +#include "audio_dma.hpp" static void init() { // Audio DMA initialization was moved to baseband proc's that actually use DMA audio, to save memory. @@ -65,6 +66,8 @@ void __late_init(void) { void _default_exit(void) { // TODO: Is this complete? + audio::dma::disable(); + nvicDisableVector(DMA_IRQn); chSysDisable(); From 74442f197d5ae8266151304bd8880d9104d51fda Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Tue, 19 Mar 2024 04:53:55 -0500 Subject: [PATCH 51/98] Fixed Sonde RSSI "Beep" (#2012) --- firmware/application/apps/ui_sonde.cpp | 2 + firmware/baseband/audio_dma.cpp | 15 ++++++ firmware/baseband/audio_dma.hpp | 2 + firmware/baseband/proc_sonde.cpp | 58 ++---------------------- firmware/baseband/proc_sonde.hpp | 32 +------------ firmware/baseband/tone_gen.cpp | 63 ++++---------------------- firmware/baseband/tone_gen.hpp | 32 +++---------- 7 files changed, 40 insertions(+), 164 deletions(-) diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index b3691f1bb..25bac3560 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -72,6 +72,8 @@ SondeView::SondeView(NavigationView& nav) check_beep.on_select = [this](Checkbox&, bool v) { beep = v; + if (v) + baseband::request_beep(); }; check_log.on_select = [this](Checkbox&, bool v) { diff --git a/firmware/baseband/audio_dma.cpp b/firmware/baseband/audio_dma.cpp index f8e843b08..39df845d3 100644 --- a/firmware/baseband/audio_dma.cpp +++ b/firmware/baseband/audio_dma.cpp @@ -25,9 +25,11 @@ #include #include #include +#include #include "hal.h" #include "gpdma.hpp" +#include "tone_gen.hpp" using namespace lpc43xx; @@ -36,6 +38,8 @@ using namespace lpc43xx; namespace audio { namespace dma { +ToneGen tone_gen{}; + constexpr uint32_t gpdma_ahb_master_peripheral = 1; constexpr uint32_t gpdma_ahb_master_memory = 0; constexpr uint32_t gpdma_ahb_master_lli_fetch = 0; @@ -229,6 +233,17 @@ void shrink_tx_buffer(bool shrink) { lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[1]); } +void beep_start(uint32_t freq, uint32_t sample_rate) { + tone_gen.configure_beep(freq, sample_rate); + + for (size_t i = 0; i < buffer_samples; i++) + buffer_tx[i].left = buffer_tx[i].right = tone_gen.process_beep(); +} + +void beep_stop() { + memset(&buffer_tx, 0, buffer_bytes); +} + buffer_t tx_empty_buffer() { const auto next_lli = tx_next_lli; if (next_lli) { diff --git a/firmware/baseband/audio_dma.hpp b/firmware/baseband/audio_dma.hpp index 41573524f..2174cd1e0 100644 --- a/firmware/baseband/audio_dma.hpp +++ b/firmware/baseband/audio_dma.hpp @@ -47,6 +47,8 @@ void init_audio_in(); void init_audio_out(); void disable(); void shrink_tx_buffer(bool shrink); +void beep_start(uint32_t freq, uint32_t sample_rate); +void beep_stop(); audio::buffer_t tx_empty_buffer(); audio::buffer_t rx_empty_buffer(); diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index 7c145ed3b..d89859b04 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -26,16 +27,12 @@ #include "event_m4.hpp" -#include "audio_output.hpp" #include "audio_dma.hpp" SondeProcessor::SondeProcessor() { decim_0.configure(taps_11k0_decim_0.taps); decim_1.configure(taps_11k0_decim_1.taps); - audio_output.configure(false); - - tone_gen.configure(BEEP_BASE_FREQ, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE); baseband_thread.start(); } @@ -55,23 +52,6 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) { clock_recovery_fsk_4800(mf.get_output()); } } - - if (pitch_rssi_enabled) { - if (beep_play) { - // if we let the buffer underrun, for some reason - // once it starts looping it ignores zero (silence) - // samples, so we need to keep feeding the buffer - // and not be able to take advantage of the circular - // buffer loop: - // beep_play = false; - generate_beep(); - } - - if (silence_play) { - // silence_play = false; - generate_silence(); - } - } } void SondeProcessor::on_message(const Message* const msg) { @@ -89,9 +69,9 @@ void SondeProcessor::on_message(const Message* const msg) { beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION; } - play_beep(); + audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE); chThdSleepMilliseconds(beep_duration); - stop_beep(); + audio::dma::beep_stop(); } break; @@ -104,41 +84,11 @@ void SondeProcessor::on_message(const Message* const msg) { } } -void SondeProcessor::play_beep() { - beep_play = true; - silence_play = false; -} - -void SondeProcessor::stop_beep() { - beep_play = false; - silence_play = true; -} - -void SondeProcessor::generate_beep() { - // here we let the samples be created using the ToneGen class: - - for (uint8_t i = 0; i < sizeof(audio_buffer.p); i++) { - audio_buffer.p[i] = (int16_t)((tone_gen.process(0) >> 16) & 0x0000FFFF); - } - - audio_output.write(audio_buffer); -} - -void SondeProcessor::generate_silence() { - for (uint8_t i = 0; i < sizeof(audio_buffer.p); i++) { - audio_buffer.p[i] = 0; - } - - audio_output.write(audio_buffer); -} - void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) { pitch_rssi_enabled = message.enabled; - uint32_t freq = (int)((float)message.rssi * (float)RSSI_PITCH_WEIGHT + (float)BEEP_BASE_FREQ); - + beep_freq = (int)((float)message.rssi * (float)RSSI_PITCH_WEIGHT + (float)BEEP_BASE_FREQ); last_rssi = message.rssi; - tone_gen.configure(freq, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE); } int main() { diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp index 93ed22e12..8f9283e37 100644 --- a/firmware/baseband/proc_sonde.hpp +++ b/firmware/baseband/proc_sonde.hpp @@ -2,6 +2,7 @@ * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek * Copyright (C) 2014 zilog80 + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -88,9 +89,6 @@ #include "message.hpp" #include "portapack_shared_memory.hpp" -#include "audio_output.hpp" -#include "tone_gen.hpp" - #include "buffer.hpp" #include @@ -115,21 +113,10 @@ class SondeProcessor : public BasebandProcessor { private: static constexpr size_t baseband_fs = 2457600; - std::array audio{}; - - const buffer_s16_t audio_buffer{ - (int16_t*)audio.data(), - sizeof(audio) / sizeof(int16_t)}; - - AudioOutput audio_output{}; - - bool beep_play{false}; - bool silence_play{false}; bool pitch_rssi_enabled{false}; uint32_t last_rssi{0}; - - ToneGen tone_gen{}; + uint32_t beep_freq{0}; std::array dst{}; const buffer_c16_t dst_buffer{ @@ -181,21 +168,6 @@ class SondeProcessor : public BasebandProcessor { baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false}; RSSIThread rssi_thread{}; - void play_beep(); - void stop_beep(); - - /** - * Used for filling the audio buffer with the waveform - * generated by the ToneGen class: - * - */ - void generate_beep(); - - /** - * Used for filling the audio buffer with silence: - */ - void generate_silence(); - void pitch_rssi_config(const PitchRSSIConfigureMessage& message); }; diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index 447376637..f1b7565dd 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -23,53 +24,18 @@ #include "tone_gen.hpp" #include "sine_table_int8.hpp" -/* -int32_t ToneGen::tone_sine() { - // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde - // Hoepfully we can manage without it , same as previous fw 1.3.1 - int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000; - tone_phase_ += delta_; - - return tone_sample; +// Functions for audio beep (used by Sonde RSSI) +void ToneGen::configure_beep(const uint32_t freq, const uint32_t sample_rate) { + f_delta_ = (float)(freq * sizeof(sine_table_i8)) / sample_rate; } -*/ -int32_t ToneGen::tone_square() { - // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde - int32_t tone_sample = 0; - - if (tone_phase_ < (UINT32_MAX / 2)) { - tone_sample = INT32_MAX; - } else { - tone_sample = INT32_MIN; - } - - tone_phase_ += delta_; +int16_t ToneGen::process_beep() { + int16_t tone_sample = sine_table_i8[(uint32_t)f_tone_phase_ & 0xFF] * 256; + f_tone_phase_ += f_delta_; return tone_sample; } -/* -void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { - // Confirmed ! It is not working well in the fw 1.4.4 Mic App , CTCSS generation, (but added for Sonde App) - // I Think it should be deleted or modified but not use it as it is in Mic App . - - delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24); - delta_ = delta; - tone_mix_weight_ = tone_mix_weight; - input_mix_weight_ = 1.0 - tone_mix_weight; - current_tone_type_ = sine; -} -*/ - -void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) { - // TODO : Added for Sonde App. We keep it by now to avoid compile errors, but it needs to be reviewed in Sonde - delta_ = (uint8_t)((freq * sizeof(sine_table_i8)) / sample_rate); - tone_mix_weight_ = tone_mix_weight; - input_mix_weight_ = 1.0 - tone_mix_weight; - current_tone_type_ = tone_type; -} - // ----Original available core SW code from fw 1.3.1 , Working also well in Mic App CTCSS Gen from fw 1.4.0 onwards // Original direct-look-up synthesis algorithm with Fractional delta phase. It is OK @@ -90,17 +56,4 @@ int32_t ToneGen::process(const int32_t sample_in) { tone_phase_ += delta_; return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); -} -// ------------------------------------------------------------- - -int32_t ToneGen::process_square(const int32_t sample_in) { - // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde - if (!delta_) - return sample_in; - - int32_t tone_sample = 0; - - tone_sample = tone_square(); - - return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); -} +} \ No newline at end of file diff --git a/firmware/baseband/tone_gen.hpp b/firmware/baseband/tone_gen.hpp index 2bbb7a5ae..d688e2548 100644 --- a/firmware/baseband/tone_gen.hpp +++ b/firmware/baseband/tone_gen.hpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -28,40 +29,21 @@ class ToneGen { public: - enum tone_type { sine, - square }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. - - /*ToneGen(const size_t sample_rate - ) : sample_rate_ { sample_rate } - {};*/ - void configure(const uint32_t delta, const float tone_mix_weight); - void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate); - int32_t process(const int32_t sample_in); - int32_t process_square(const int32_t sample_in); + + void configure_beep(const uint32_t freq, const uint32_t sample_rate); + int16_t process_beep(); private: - tone_type current_tone_type_{sine}; - float input_mix_weight_{1}; float tone_mix_weight_{0}; + float f_delta_{0.0}; + float f_tone_phase_{0.0}; + uint32_t delta_{0}; uint32_t tone_phase_{0}; - - // uint8_t delta_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. - // uint8_t tone_phase_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. - - /** - * Generator function which selects every other sample from the reference sine waveform to the output sample: - */ - int32_t tone_sine(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. - - /** - * Generator function for square waves: - */ - int32_t tone_square(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. }; #endif /* __TONE_GEN_H__ */ From 308573918cd399d4b45e97c5d5316797794cd3c2 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:23:06 -0500 Subject: [PATCH 52/98] Added a beep duration parameter (#2013) --- firmware/baseband/audio_dma.cpp | 12 +++++++++++- firmware/baseband/audio_dma.hpp | 2 +- firmware/baseband/proc_sonde.cpp | 6 ++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/firmware/baseband/audio_dma.cpp b/firmware/baseband/audio_dma.cpp index 39df845d3..56c70c428 100644 --- a/firmware/baseband/audio_dma.cpp +++ b/firmware/baseband/audio_dma.cpp @@ -149,9 +149,14 @@ static volatile const gpdma::channel::LLI* tx_next_lli = nullptr; static volatile const gpdma::channel::LLI* rx_next_lli = nullptr; static bool single_tx_buffer = false; +static uint32_t beep_duration_downcounter = 0; static void tx_transfer_complete() { tx_next_lli = gpdma_channel_i2s0_tx.next_lli(); + + if (beep_duration_downcounter != 0) + if (--beep_duration_downcounter == 0) + beep_stop(); } static void tx_error() { @@ -233,11 +238,16 @@ void shrink_tx_buffer(bool shrink) { lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[1]); } -void beep_start(uint32_t freq, uint32_t sample_rate) { +void beep_start(uint32_t freq, uint32_t sample_rate, uint32_t beep_duration_ms) { tone_gen.configure_beep(freq, sample_rate); for (size_t i = 0; i < buffer_samples; i++) buffer_tx[i].left = buffer_tx[i].right = tone_gen.process_beep(); + + uint32_t beep_interrupt_count = beep_duration_ms * sample_rate / (1000 * transfer_samples); + if ((beep_duration_ms != 0) && (beep_interrupt_count == 0)) + beep_interrupt_count = 1; + beep_duration_downcounter = beep_interrupt_count; } void beep_stop() { diff --git a/firmware/baseband/audio_dma.hpp b/firmware/baseband/audio_dma.hpp index 2174cd1e0..4c98042ff 100644 --- a/firmware/baseband/audio_dma.hpp +++ b/firmware/baseband/audio_dma.hpp @@ -47,7 +47,7 @@ void init_audio_in(); void init_audio_out(); void disable(); void shrink_tx_buffer(bool shrink); -void beep_start(uint32_t freq, uint32_t sample_rate); +void beep_start(uint32_t freq, uint32_t sample_rate, uint32_t beep_duration_ms); void beep_stop(); audio::buffer_t tx_empty_buffer(); diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index d89859b04..1f43be2ea 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -59,7 +59,7 @@ void SondeProcessor::on_message(const Message* const msg) { case Message::ID::RequestSignal: if ((*reinterpret_cast(msg)).signal == RequestSignalMessage::Signal::BeepRequest) { float rssi_ratio = (float)last_rssi / (float)RSSI_CEILING; - int beep_duration = 0; + uint32_t beep_duration = 0; if (rssi_ratio <= PROPORTIONAL_BEEP_THRES) { beep_duration = BEEP_MIN_DURATION; @@ -69,9 +69,7 @@ void SondeProcessor::on_message(const Message* const msg) { beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION; } - audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE); - chThdSleepMilliseconds(beep_duration); - audio::dma::beep_stop(); + audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE, beep_duration); } break; From 807c76346bc71c0634584c5482a3dda0e291924b Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:30:05 -0500 Subject: [PATCH 53/98] Improved audio beep tone (#2014) * Improved sine wave beep tone * Prevent divide-by-zero --- firmware/baseband/audio_dma.cpp | 26 ++++++++++++++++++++++++-- firmware/baseband/tone_gen.cpp | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/firmware/baseband/audio_dma.cpp b/firmware/baseband/audio_dma.cpp index 56c70c428..990f49f7d 100644 --- a/firmware/baseband/audio_dma.cpp +++ b/firmware/baseband/audio_dma.cpp @@ -239,19 +239,41 @@ void shrink_tx_buffer(bool shrink) { } void beep_start(uint32_t freq, uint32_t sample_rate, uint32_t beep_duration_ms) { - tone_gen.configure_beep(freq, sample_rate); + // Prevent divide-by-0 + if (freq == 0 || sample_rate == 0) + return; + // Fill entire buffer with sine waves + tone_gen.configure_beep(freq, sample_rate); for (size_t i = 0; i < buffer_samples; i++) buffer_tx[i].left = buffer_tx[i].right = tone_gen.process_beep(); - uint32_t beep_interrupt_count = beep_duration_ms * sample_rate / (1000 * transfer_samples); + // Try to adjust DMA transfer count to align with full sine waves for a better tone + float samples_per_sine_wave = float(sample_rate) / freq; + uint32_t sine_waves_per_buffer = buffer_samples / samples_per_sine_wave; + size_t sample_count = (sine_waves_per_buffer == 0) ? buffer_samples : sine_waves_per_buffer * samples_per_sine_wave + 0.5; + + // Use single larger transfer buffer with sample count determined above + lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[0]); + lli_tx_loop[0].control = control_tx(sample_count * sizeof(sample_t)); + + // Convert duration ms to number of buffers to send before stopping + // NB: beep_duration_ms==0 means beep continuously until stopped + uint32_t beep_interrupt_count = beep_duration_ms * sample_rate / (1000 * sample_count); if ((beep_duration_ms != 0) && (beep_interrupt_count == 0)) beep_interrupt_count = 1; beep_duration_downcounter = beep_interrupt_count; } void beep_stop() { + // Clear audio DMA buffer memset(&buffer_tx, 0, buffer_bytes); + + // Restore DMA linked list to use multiple smaller buffers + lli_tx_loop[0].control = control_tx(transfer_bytes); + if (!single_tx_buffer && (transfers_per_buffer > 1)) { + lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[1]); + } } buffer_t tx_empty_buffer() { diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index f1b7565dd..efe74c66d 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -27,6 +27,7 @@ // Functions for audio beep (used by Sonde RSSI) void ToneGen::configure_beep(const uint32_t freq, const uint32_t sample_rate) { f_delta_ = (float)(freq * sizeof(sine_table_i8)) / sample_rate; + f_tone_phase_ = 0.0; } int16_t ToneGen::process_beep() { @@ -44,6 +45,7 @@ int16_t ToneGen::process_beep() { void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { delta_ = delta; + tone_phase_ = 0; tone_mix_weight_ = tone_mix_weight; input_mix_weight_ = 1.0 - tone_mix_weight; } From 8391ca8052883e4aa20faccecb6fda122b444536 Mon Sep 17 00:00:00 2001 From: Totoo Date: Tue, 19 Mar 2024 21:33:53 +0100 Subject: [PATCH 54/98] Fox hunt (#2015) * foxhunt_rx --- firmware/application/external/external.cmake | 7 ++ firmware/application/external/external.ld | 7 ++ .../application/external/foxhunt/main.cpp | 82 ++++++++++++ .../external/foxhunt/ui_foxhunt_rx.cpp | 107 ++++++++++++++++ .../external/foxhunt/ui_foxhunt_rx.hpp | 118 ++++++++++++++++++ 5 files changed, 321 insertions(+) create mode 100644 firmware/application/external/foxhunt/main.cpp create mode 100644 firmware/application/external/foxhunt/ui_foxhunt_rx.cpp create mode 100644 firmware/application/external/foxhunt/ui_foxhunt_rx.hpp diff --git a/firmware/application/external/external.cmake b/firmware/application/external/external.cmake index b37b0f081..a84fa9319 100644 --- a/firmware/application/external/external.cmake +++ b/firmware/application/external/external.cmake @@ -67,6 +67,12 @@ set(EXTCPPSRC external/extsensors/main.cpp external/extsensors/ui_extsensors.cpp external/extsensors/ui_extsensors.hpp + + #foxhunt + external/foxhunt/main.cpp + external/foxhunt/ui_foxhunt_rx.cpp + external/foxhunt/ui_foxhunt_rx.hpp + ) set(EXTAPPLIST @@ -86,4 +92,5 @@ set(EXTAPPLIST keyfob tetris extsensors + foxhunt_rx ) diff --git a/firmware/application/external/external.ld b/firmware/application/external/external.ld index 3249ea45c..c75276f39 100644 --- a/firmware/application/external/external.ld +++ b/firmware/application/external/external.ld @@ -39,6 +39,7 @@ MEMORY 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 + ram_external_app_foxhunt_rx(rwx) : org = 0xADC00000, len = 32k } SECTIONS @@ -139,6 +140,12 @@ SECTIONS *(*ui*external_app*extsensors*); } > ram_external_app_extsensors + .external_app_foxhunt_rx : ALIGN(4) SUBALIGN(4) + { + KEEP(*(.external_app.app_foxhunt_rx.application_information)); + *(*ui*external_app*foxhunt_rx*); + } > ram_external_app_foxhunt_rx + } diff --git a/firmware/application/external/foxhunt/main.cpp b/firmware/application/external/foxhunt/main.cpp new file mode 100644 index 000000000..1f6528469 --- /dev/null +++ b/firmware/application/external/foxhunt/main.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 HTotoo + * + * 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_foxhunt_rx.hpp" +#include "ui_navigation.hpp" +#include "external_app.hpp" + +namespace ui::external_app::foxhunt_rx { +void initialize_app(ui::NavigationView& nav) { + nav.push(); +} +} // namespace ui::external_app::foxhunt_rx + +extern "C" { + +__attribute__((section(".external_app.app_foxhunt_rx.application_information"), used)) application_information_t _application_information_foxhunt_rx = { + /*.memory_location = */ (uint8_t*)0x00000000, + /*.externalAppEntry = */ ui::external_app::foxhunt_rx::initialize_app, + /*.header_version = */ CURRENT_HEADER_VERSION, + /*.app_version = */ VERSION_MD5, + + /*.app_name = */ "Fox hunt", + /*.bitmap_data = */ { + 0x18, + 0x18, + 0x28, + 0x14, + 0x68, + 0x16, + 0x68, + 0x16, + 0xC8, + 0x13, + 0x88, + 0x11, + 0x04, + 0x20, + 0x24, + 0x24, + 0x22, + 0x44, + 0x01, + 0x80, + 0x06, + 0x60, + 0x98, + 0x19, + 0x20, + 0x04, + 0x40, + 0x02, + 0x80, + 0x01, + 0x00, + 0x00, + }, + /*.icon_color = */ ui::Color::yellow().v, + /*.menu_location = */ app_location_t::RX, + + /*.m4_app_tag = portapack::spi_flash::image_tag_am_audio */ {'P', 'A', 'M', 'A'}, + /*.m4_app_offset = */ 0x00000000, // will be filled at compile time +}; +} diff --git a/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp b/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp new file mode 100644 index 000000000..cac19c305 --- /dev/null +++ b/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2024 HTotoo + * + * 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_foxhunt_rx.hpp" + +#include "audio.hpp" +#include "rtc_time.hpp" +#include "baseband_api.hpp" +#include "string_format.hpp" +#include "portapack_persistent_memory.hpp" + +using namespace portapack; +using namespace modems; +using namespace ui; + +namespace ui::external_app::foxhunt_rx { + +void FoxhuntRxView::focus() { + field_frequency.focus(); +} + +FoxhuntRxView::FoxhuntRxView(NavigationView& nav) + : nav_{nav} { + baseband::run_image(portapack::spi_flash::image_tag_am_audio); + + add_children({&rssi, + &field_rf_amp, + &field_lna, + &field_vga, + &field_volume, + &field_frequency, + &freq_stats_db, + &rssi_graph, + &geomap, + &clear_markers, + &add_current_marker}); + + clear_markers.on_select = [this](Button&) { + geomap.clear_markers(); + }; + add_current_marker.on_select = [this](Button&) { + GeoMarker tmp{my_lat, my_lon, my_orientation}; + geomap.store_marker(tmp); + }; + geomap.set_mode(DISPLAY); + geomap.set_manual_panning(false); + // geomap.set_enable_additional_zoom(true); + // geomap.set_hide_center_marker(true); //todo hide again after testing + geomap.set_focusable(true); + geomap.clear_markers(); + receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); + field_frequency.set_step(100); + receiver_model.enable(); + audio::output::start(); + rssi_graph.set_nb_columns(64); + geomap.init(); +} + +FoxhuntRxView::~FoxhuntRxView() { + receiver_model.disable(); + baseband::shutdown(); + audio::output::stop(); +} + +void FoxhuntRxView::on_statistics_update(const ChannelStatistics& statistics) { + static int16_t last_max_db = -1000; + rssi_graph.add_values(rssi.get_min(), rssi.get_avg(), rssi.get_max(), statistics.max_db); + // refresh db + if (last_max_db != statistics.max_db) { + last_max_db = statistics.max_db; + freq_stats_db.set("Power: " + to_string_dec_int(statistics.max_db) + " db"); + } + +} /* on_statistic_updates */ + +void FoxhuntRxView::on_gps(const GPSPosDataMessage* msg) { + my_lat = msg->lat; + my_lon = msg->lon; + geomap.update_my_position(msg->lat, msg->lon, msg->altitude); + geomap.move(my_lon, my_lat); + geomap.set_dirty(); +} +void FoxhuntRxView::on_orientation(const OrientationDataMessage* msg) { + my_orientation = msg->angle; + geomap.set_angle(msg->angle); + geomap.update_my_orientation(msg->angle, true); +} + +} // namespace ui::external_app::foxhunt_rx diff --git a/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp b/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp new file mode 100644 index 000000000..ba47086d2 --- /dev/null +++ b/firmware/application/external/foxhunt/ui_foxhunt_rx.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 HTotoo + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_FOXHUNT_RX_H__ +#define __UI_FOXHUNT_RX_H__ + +#include "ui.hpp" +#include "ui_language.hpp" +#include "ui_navigation.hpp" +#include "ui_receiver.hpp" +#include "ui_geomap.hpp" +#include "ui_freq_field.hpp" +#include "ui_record_view.hpp" +#include "app_settings.hpp" +#include "radio_state.hpp" +#include "log_file.hpp" +#include "utility.hpp" + +using namespace ui; + +namespace ui::external_app::foxhunt_rx { + +class FoxhuntRxView : public View { + public: + FoxhuntRxView(NavigationView& nav); + ~FoxhuntRxView(); + + void focus() override; + + std::string title() const override { return "Fox hunt"; }; + + private: + NavigationView& nav_; + RxRadioState radio_state_{}; + app_settings::SettingsManager settings_{ + "rx_foxhunt", app_settings::Mode::RX}; + + RFAmpField field_rf_amp{ + {13 * 8, 0 * 16}}; + LNAGainField field_lna{ + {15 * 8, 0 * 16}}; + VGAGainField field_vga{ + {18 * 8, 0 * 16}}; + RSSI rssi{ + {21 * 8, 0, 6 * 8, 4}}; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + + RxFrequencyField field_frequency{ + {0 * 8, 0 * 16}, + nav_}; + + // Power: -XXX db + Text freq_stats_db{ + {0 * 8, 2 * 16 + 4, 14 * 8, 14}, + }; + RSSIGraph rssi_graph{ + {0, 50, 240, 30}, + }; + + Button clear_markers{ + {10 * 8, 18, 8 * 8, 16}, + LanguageHelper::currentMessages[LANG_CLEAR]}; + + Button add_current_marker{ + {2, 18, 7 * 8, 16}, + "Mark"}; + + GeoMap geomap{{0, 80, 240, 240}}; + + MessageHandlerRegistration message_handler_gps{ + Message::ID::GPSPosData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_gps(message); + }}; + MessageHandlerRegistration message_handler_orientation{ + Message::ID::OrientationData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_orientation(message); + }}; + MessageHandlerRegistration message_handler_stats{ + Message::ID::ChannelStatistics, + [this](const Message* const p) { + this->on_statistics_update(static_cast(p)->statistics); + }}; + + float my_lat = 200; + float my_lon = 200; + uint16_t my_orientation = 400; + + void on_gps(const GPSPosDataMessage* msg); + void on_orientation(const OrientationDataMessage* msg); + void on_statistics_update(const ChannelStatistics& statistics); +}; + +} // namespace ui::external_app::foxhunt_rx + +#endif /*__UI_FOXHUNT_RX_H__*/ From 4aeaf94d2d9690e59ab2fb47b6b74335952a84ba Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Thu, 21 Mar 2024 04:14:54 -0500 Subject: [PATCH 55/98] Radiosonde beep tone tweaks (#2020) * Tweak RSSI audio beep frequency range * Clang & changed min freq * Save beep/log/crc settings in .ini file * Update copyright string * Added generic audio_beep message --- firmware/application/apps/ui_mictx.cpp | 6 ++-- firmware/application/apps/ui_sonde.cpp | 10 ++++-- firmware/application/apps/ui_sonde.hpp | 17 +++++++--- firmware/application/baseband_api.cpp | 21 ++++++++++-- firmware/application/baseband_api.hpp | 6 +++- firmware/baseband/proc_mictx.cpp | 2 +- firmware/baseband/proc_sonde.cpp | 44 ++++++++++++++++---------- firmware/baseband/proc_sonde.hpp | 10 ++++-- firmware/common/message.hpp | 19 +++++++++-- 9 files changed, 99 insertions(+), 36 deletions(-) diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index c7b47c35a..e72e63a0a 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -130,9 +130,9 @@ void MicTXView::set_tx(bool enable) { portapack::pin_i2s0_rx_sda.mode(3); // This is already done in audio::init but gets changed by the CPLD overlay reprogramming } else { if (transmitting && rogerbeep_enabled) { - baseband::request_beep(); // Transmit the roger beep - transmitting = false; // And flag the end of the transmission so ... - } else { // (if roger beep was enabled, this will be executed after the beep ends transmitting. + baseband::request_roger_beep(); // Transmit the roger beep + transmitting = false; // Flag the end of the transmission (transmitter will be disabled after the beep) + } else { transmitting = false; configure_baseband(); transmitter_model.disable(); diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 25bac3560..499bd39e9 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -70,16 +71,19 @@ SondeView::SondeView(NavigationView& nav) geopos.set_read_only(true); + check_beep.set_value(beep); check_beep.on_select = [this](Checkbox&, bool v) { beep = v; - if (v) - baseband::request_beep(); + if (beep) + baseband::request_audio_beep(1000, 60); // 1khz tone for 60ms to acknowledge enablement }; + check_log.set_value(logging); check_log.on_select = [this](Checkbox&, bool v) { logging = v; }; + check_crc.set_value(use_crc); check_crc.on_select = [this](Checkbox&, bool v) { use_crc = v; }; @@ -222,7 +226,7 @@ void SondeView::on_packet(const sonde::Packet& packet) { } if (beep) { - baseband::request_beep(); + baseband::request_rssi_beep(); } } } diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index aa5e3e349..718a8dc97 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2017 Furrtek + * Copyright (C) 2024 Mark Thompson * * This file is part of PortaPack. * @@ -74,13 +75,19 @@ class SondeView : public View { 1750000 /* bandwidth */, 2457600 /* sampling rate */ }; - app_settings::SettingsManager settings_{ - "rx_sonde", app_settings::Mode::RX}; - - std::unique_ptr logger{}; + bool beep{false}; bool logging{false}; bool use_crc{false}; - bool beep{false}; + app_settings::SettingsManager settings_{ + "rx_sonde", + app_settings::Mode::RX, + { + {"beep"sv, &beep}, + {"logging"sv, &logging}, + {"use_crc"sv, &use_crc}, + }}; + + std::unique_ptr logger{}; char geo_uri[32] = {}; diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 452891257..0095189da 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -428,8 +428,25 @@ void replay_stop() { send_message(&message); } -void request_beep() { - RequestSignalMessage message{RequestSignalMessage::Signal::BeepRequest}; +void request_beep(RequestSignalMessage::Signal beep_type) { + RequestSignalMessage message{beep_type}; + send_message(&message); +} + +void request_roger_beep() { + request_beep(RequestSignalMessage::Signal::RogerBeepRequest); +} + +void request_rssi_beep() { + request_beep(RequestSignalMessage::Signal::RSSIBeepRequest); +} + +void request_beep_stop() { + request_beep(RequestSignalMessage::Signal::BeepStopRequest); +} + +void request_audio_beep(uint32_t freq, uint32_t duration_ms) { + AudioBeepMessage message{freq, duration_ms}; send_message(&message); } diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 48428f7e5..50e2282e8 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -89,7 +89,11 @@ void set_siggen_tone(const uint32_t tone); void set_siggen_config(const uint32_t bw, const uint32_t shape, const uint32_t duration); void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bool update, int32_t bw); void set_subghzd_config(uint8_t modulation, uint32_t sampling_rate); -void request_beep(); + +void request_roger_beep(); +void request_rssi_beep(); +void request_beep_stop(); +void request_audio_beep(uint32_t freq, uint32_t duration_ms); void run_image(const portapack::spi_flash::image_tag_t image_tag); void run_prepared_image(const uint32_t m4_code); diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index 9f0d37718..b2705d03b 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -155,7 +155,7 @@ void MicTXProcessor::on_message(const Message* const msg) { break; case Message::ID::RequestSignal: - if (request_message.signal == RequestSignalMessage::Signal::BeepRequest) { + if (request_message.signal == RequestSignalMessage::Signal::RogerBeepRequest) { beep_index = 0; beep_timer = 0; play_beep = true; diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index 1f43be2ea..a40359d7d 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -57,24 +57,15 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) { void SondeProcessor::on_message(const Message* const msg) { switch (msg->id) { case Message::ID::RequestSignal: - if ((*reinterpret_cast(msg)).signal == RequestSignalMessage::Signal::BeepRequest) { - float rssi_ratio = (float)last_rssi / (float)RSSI_CEILING; - uint32_t beep_duration = 0; + on_signal_message(*reinterpret_cast(msg)); + break; - if (rssi_ratio <= PROPORTIONAL_BEEP_THRES) { - beep_duration = BEEP_MIN_DURATION; - } else if (rssi_ratio < 1) { - beep_duration = (int)rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION; - } else { - beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION; - } - - audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE, beep_duration); - } + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(msg)); break; case Message::ID::PitchRSSIConfigure: - pitch_rssi_config(*reinterpret_cast(msg)); + on_pitch_rssi_config(*reinterpret_cast(msg)); break; default: @@ -82,10 +73,31 @@ void SondeProcessor::on_message(const Message* const msg) { } } -void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) { +void SondeProcessor::on_signal_message(const RequestSignalMessage& message) { + if (message.signal == RequestSignalMessage::Signal::RSSIBeepRequest) { + float rssi_ratio = (float)last_rssi / RSSI_CEILING; + uint32_t beep_duration = 0; + + if (rssi_ratio <= PROPORTIONAL_BEEP_THRES) { + beep_duration = BEEP_MIN_DURATION; + } else if (rssi_ratio < 1) { + beep_duration = rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION; + } else { + beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION; + } + + audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE, beep_duration); + } +} + +void SondeProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, AUDIO_SAMPLE_RATE, message.duration_ms); +} + +void SondeProcessor::on_pitch_rssi_config(const PitchRSSIConfigureMessage& message) { pitch_rssi_enabled = message.enabled; - beep_freq = (int)((float)message.rssi * (float)RSSI_PITCH_WEIGHT + (float)BEEP_BASE_FREQ); + beep_freq = message.rssi * RSSI_PITCH_WEIGHT + BEEP_BASE_FREQ; last_rssi = message.rssi; } diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp index 8f9283e37..7b6784139 100644 --- a/firmware/baseband/proc_sonde.hpp +++ b/firmware/baseband/proc_sonde.hpp @@ -97,10 +97,12 @@ #define BEEP_MIN_DURATION 60 #define BEEP_DURATION_RANGE 100 -#define BEEP_BASE_FREQ 200 +#define BEEP_BASE_FREQ 400 // Lowest audible freq for some PortaPack speakers +#define BEEP_MAX_FREQ 8000 // Highest audible freq for some PortaPack speakers +#define BEEP_SIMPLE_FREQ 1000 #define RSSI_CEILING 1000 #define PROPORTIONAL_BEEP_THRES 0.8 -#define RSSI_PITCH_WEIGHT 0.5 +#define RSSI_PITCH_WEIGHT (float(BEEP_MAX_FREQ - BEEP_BASE_FREQ) / RSSI_CEILING) #define AUDIO_SAMPLE_RATE 24000 class SondeProcessor : public BasebandProcessor { @@ -168,7 +170,9 @@ class SondeProcessor : public BasebandProcessor { baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false}; RSSIThread rssi_thread{}; - void pitch_rssi_config(const PitchRSSIConfigureMessage& message); + void on_signal_message(const RequestSignalMessage& message); + void on_beep_message(const AudioBeepMessage& message); + void on_pitch_rssi_config(const PitchRSSIConfigureMessage& message); }; #endif /*__PROC_ERT_H__*/ diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 717fb50b2..1bf4e12da 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -121,6 +121,7 @@ class Message { GPSPosData = 63, OrientationData = 64, EnvironmentData = 65, + AudioBeep = 66, MAX }; @@ -1165,8 +1166,10 @@ class RequestSignalMessage : public Message { public: enum class Signal : char { FillRequest = 1, - BeepRequest = 2, - Squelched = 3 + RogerBeepRequest = 2, + RSSIBeepRequest = 3, + BeepStopRequest = 4, + Squelched = 5, }; constexpr RequestSignalMessage( @@ -1361,4 +1364,16 @@ class EnvironmentDataMessage : public Message { uint16_t light = 0; // lux }; +class AudioBeepMessage : public Message { + public: + constexpr AudioBeepMessage( + uint32_t freq = 1000, + uint32_t duration_ms = 100) + : Message{ID::AudioBeep}, + freq{freq}, + duration_ms{duration_ms} { + } + uint32_t freq = 1000; + uint32_t duration_ms = 100; +}; #endif /*__MESSAGE_H__*/ From 692644d214cf57e38e8ff24a27eec13256c2efa4 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:56:06 -0500 Subject: [PATCH 56/98] Radiosonde QR code fixes (#2021) * Increase size of small QR Code * Fixed QR code lat/lon for iPhone * Show current geopos location on map * Deprecate large QR code --- firmware/application/apps/ui_settings.cpp | 2 +- firmware/application/apps/ui_sonde.cpp | 51 +++-------------------- firmware/application/apps/ui_sonde.hpp | 3 -- firmware/application/ui/ui_qrcode.cpp | 42 ++++--------------- 4 files changed, 15 insertions(+), 83 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index a4479fe81..36bca5adb 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -858,7 +858,7 @@ void SettingsMenuView::on_populate() { {"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push(); }}, {"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push(); }}, - {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push(); }}, + //{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push(); }}, {"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, {"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, }); diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 499bd39e9..5b09af432 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -92,17 +92,18 @@ SondeView::SondeView(NavigationView& nav) // QR code with geo URI button_see_qr.on_select = [this, &nav](Button&) { - nav.push(geo_uri); + std::string geo_uri = "geo:" + to_string_decimal(geopos.lat(), 5) + "," + to_string_decimal(geopos.lon(), 5); // 5 decimal digits for ~1 meter accuracy + nav.push(geo_uri.data()); }; button_see_map.on_select = [this, &nav](Button&) { geomap_view_ = nav.push( sonde_id, - gps_info.alt, + geopos.altitude(), GeoPos::alt_unit::METERS, GeoPos::spd_unit::HIDDEN, - gps_info.lat, - gps_info.lon, + geopos.lat(), + geopos.lon(), 999); // set a dummy heading out of range to draw a cross...probably not ideal? nav.set_on_pop([this]() { geomap_view_ = nullptr; @@ -148,51 +149,9 @@ void SondeView::focus() { field_frequency.focus(); } -// used to convert float to character pointer, since unfortunately function like -// sprintf and c_str aren't supported. -char* SondeView::float_to_char(float x, char* p) { - char* s = p + 9; // go to end of buffer - uint16_t decimals; // variable to store the decimals - int units; // variable to store the units (part to left of decimal place) - if (x < 0) { // take care of negative numbers - decimals = (int)(x * -100000) % 100000; // make 1000 for 3 decimals etc. - units = (int)(-1 * x); - } else { // positive numbers - decimals = (int)(x * 100000) % 100000; - units = (int)x; - } - - // TODO: more elegant solution (loop?) - *--s = (decimals % 10) + '0'; - decimals /= 10; - *--s = (decimals % 10) + '0'; - decimals /= 10; - *--s = (decimals % 10) + '0'; - decimals /= 10; - *--s = (decimals % 10) + '0'; - decimals /= 10; - *--s = (decimals % 10) + '0'; - *--s = '.'; - - while (units > 0) { - *--s = (units % 10) + '0'; - units /= 10; - } - if (x < 0) *--s = '-'; // unary minus sign for negative numbers - return s; -} - void SondeView::on_packet(const sonde::Packet& packet) { if (!use_crc || packet.crc_ok()) // euquiq: Reject bad packet if crc is on { - char buffer_lat[10] = {}; - char buffer_lon[10] = {}; - - strcpy(geo_uri, "geo:"); - strcat(geo_uri, float_to_char(gps_info.lat, buffer_lat)); - strcat(geo_uri, ","); - strcat(geo_uri, float_to_char(gps_info.lon, buffer_lon)); - text_signature.set(packet.type_string()); sonde_id = packet.serial_number(); // used also as tag on the geomap diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index 718a8dc97..100eadfe6 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -89,8 +89,6 @@ class SondeView : public View { std::unique_ptr logger{}; - char geo_uri[32] = {}; - sonde::GPS_data gps_info{}; sonde::temp_humid temp_humid_info{}; std::string sonde_id{}; @@ -208,7 +206,6 @@ class SondeView : public View { void on_gps(const GPSPosDataMessage* msg); void on_orientation(const OrientationDataMessage* msg); void on_packet(const sonde::Packet& packet); - char* float_to_char(float x, char* p); }; } /* namespace ui */ diff --git a/firmware/application/ui/ui_qrcode.cpp b/firmware/application/ui/ui_qrcode.cpp index 9d55d0b9d..d1add400d 100644 --- a/firmware/application/ui/ui_qrcode.cpp +++ b/firmware/application/ui/ui_qrcode.cpp @@ -59,43 +59,19 @@ void QRCodeImage::paint(Painter& painter) { // The structure to manage the QR code QRCode qrcode; - // Either small or large QR code can be shown.. + int qr_version = 10; - if (portapack::persistent_memory::show_bigger_qr_code()) { // show large QR code - int qr_version = 2; + // Allocate a chunk of memory to store the QR code + uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)]; - // Allocate a chunk of memory to store the QR code - uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)]; + qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_); - qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_); + display.fill_rectangle(Rect(57, 65, 126, 127), Color::white()); - display.fill_rectangle(Rect(10, 30, 220, 220), Color::white()); - - for (uint8_t y = 0; y < qrcode.size; y++) { - for (uint8_t x = 0; x < qrcode.size; x++) { - if (qrcode_getModule(&qrcode, x, y)) { - display.fill_rectangle(Rect(20 + (x * 8), 40 + (y * 8), 8, 8), Color::black()); - } - } - } - - } - - else { // show small QR code - int qr_version = 10; - - // Allocate a chunk of memory to store the QR code - uint8_t qrcodeBytes[qrcode_getBufferSize(qr_version)]; - - qrcode_initText(&qrcode, qrcodeBytes, qr_version, ECC_HIGH, qr_text_); - - display.fill_rectangle(Rect(92, 97, 63, 63), Color::white()); - - for (uint8_t y = 0; y < qrcode.size; y++) { - for (uint8_t x = 0; x < qrcode.size; x++) { - if (qrcode_getModule(&qrcode, x, y)) { - display.draw_pixel(Point(95 + x, 100 + y), Color::black()); - } + for (uint8_t y = 0; y < qrcode.size; y++) { + for (uint8_t x = 0; x < qrcode.size; x++) { + if (qrcode_getModule(&qrcode, x, y)) { + display.fill_rectangle(Rect(63 + (x * 2), 71 + (y * 2), 2, 2), Color::black()); } } } From ba4290cf0dcb5cd77548bf6717ae3393b2824230 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 22 Mar 2024 05:10:16 -0500 Subject: [PATCH 57/98] Audio Beep Test (Debug) external app (#2023) --- .../application/external/audio_test/main.cpp | 82 ++++++++++++++++++ .../external/audio_test/ui_audio_test.cpp | 82 ++++++++++++++++++ .../external/audio_test/ui_audio_test.hpp | 83 +++++++++++++++++++ firmware/application/external/external.cmake | 4 + firmware/application/external/external.ld | 7 +- firmware/baseband/CMakeLists.txt | 7 +- firmware/baseband/proc_audio_beep.cpp | 63 ++++++++++++++ firmware/baseband/proc_audio_beep.hpp | 41 +++++++++ firmware/common/spi_image.hpp | 1 + 9 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 firmware/application/external/audio_test/main.cpp create mode 100644 firmware/application/external/audio_test/ui_audio_test.cpp create mode 100644 firmware/application/external/audio_test/ui_audio_test.hpp create mode 100644 firmware/baseband/proc_audio_beep.cpp create mode 100644 firmware/baseband/proc_audio_beep.hpp diff --git a/firmware/application/external/audio_test/main.cpp b/firmware/application/external/audio_test/main.cpp new file mode 100644 index 000000000..48554ce19 --- /dev/null +++ b/firmware/application/external/audio_test/main.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui.hpp" +#include "ui_audio_test.hpp" +#include "ui_navigation.hpp" +#include "external_app.hpp" + +namespace ui::external_app::audio_test { +void initialize_app(ui::NavigationView& nav) { + nav.push(); +} +} // namespace ui::external_app::audio_test + +extern "C" { + +__attribute__((section(".external_app.app_audio_test.application_information"), used)) application_information_t _application_information_audio_test = { + /*.memory_location = */ (uint8_t*)0x00000000, + /*.externalAppEntry = */ ui::external_app::audio_test::initialize_app, + /*.header_version = */ CURRENT_HEADER_VERSION, + /*.app_version = */ VERSION_MD5, + + /*.app_name = */ "Audio Test", + /*.bitmap_data = */ { + 0x00, + 0x00, + 0x40, + 0x10, + 0x60, + 0x20, + 0x70, + 0x44, + 0x78, + 0x48, + 0x7F, + 0x91, + 0x7F, + 0x92, + 0x7F, + 0x92, + 0x7F, + 0x92, + 0x7F, + 0x92, + 0x7F, + 0x92, + 0x7F, + 0x91, + 0x78, + 0x48, + 0x70, + 0x44, + 0x60, + 0x20, + 0x40, + 0x10, + }, + /*.icon_color = */ ui::Color::cyan().v, + /*.menu_location = */ app_location_t::DEBUG, + + /*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'}, + /*.m4_app_offset = */ 0x00000000, // will be filled at compile time +}; +} diff --git a/firmware/application/external/audio_test/ui_audio_test.cpp b/firmware/application/external/audio_test/ui_audio_test.cpp new file mode 100644 index 000000000..66e00973c --- /dev/null +++ b/firmware/application/external/audio_test/ui_audio_test.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui_audio_test.hpp" +#include "baseband_api.hpp" +#include "audio.hpp" +#include "portapack.hpp" + +using namespace portapack; + +namespace ui { + +AudioTestView::AudioTestView(NavigationView& nav) + : nav_{nav} { + baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too + + add_children({&labels, + &field_frequency, + &field_duration, + &field_volume, + &toggle_speaker}); + + field_frequency.set_value(1000); + field_frequency.on_change = [this](int32_t v) { + (void)v; + update_audio_beep(); + }; + + field_duration.set_value(100); + field_duration.on_change = [this](int32_t v) { + (void)v; + update_audio_beep(); + }; + + toggle_speaker.on_change = [this](bool v) { + beep = v; + update_audio_beep(); + }; + + field_volume.set_value(0); + field_volume.set_value(80); + + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); +} + +AudioTestView::~AudioTestView() { + receiver_model.disable(); + baseband::shutdown(); + audio::output::stop(); +} + +void AudioTestView::focus() { + field_frequency.focus(); +} + +void AudioTestView::update_audio_beep() { + if (beep) + baseband::request_audio_beep(field_frequency.value(), field_duration.value()); + else + baseband::request_beep_stop(); +} + +} /* namespace ui */ diff --git a/firmware/application/external/audio_test/ui_audio_test.hpp b/firmware/application/external/audio_test/ui_audio_test.hpp new file mode 100644 index 000000000..34e36870c --- /dev/null +++ b/firmware/application/external/audio_test/ui_audio_test.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_AUDIO_TEST_H__ +#define __UI_AUDIO_TEST_H__ + +#include "ui_navigation.hpp" +#include "ui_receiver.hpp" + +namespace ui { + +class AudioTestView : public View { + public: + AudioTestView(NavigationView& nav); + ~AudioTestView(); + AudioTestView(const AudioTestView& other) = delete; + AudioTestView& operator=(const AudioTestView& other) = delete; + + void focus() override; + void update_audio_beep(); + + std::string title() const override { return "Audio Test"; }; + + private: + NavigationView& nav_; + bool beep{false}; + + Labels labels{ + {{7 * 8, 3 * 16}, "Audio Beep Test", Color::light_grey()}, + {{0 * 8, 6 * 16}, "Frequency (Hz):", Color::light_grey()}, + {{0 * 8, 8 * 16}, "Duration (ms):", Color::light_grey()}, + {{0 * 8, 10 * 16}, "Volume:", Color::light_grey()}}; + + NumberField field_frequency{ + {16 * 8, 6 * 16}, + 5, + {100, 24000}, + 100, + ' ', + true}; + + NumberField field_duration{ + {16 * 8, 8 * 16}, + 5, + {0, 60000}, + 50, + ' ', + true}; + + AudioVolumeField field_volume{ + {19 * 8, 10 * 16}}; + + ImageToggle toggle_speaker{ + {19 * 8, 12 * 16, 2 * 8, 1 * 16}, + &bitmap_icon_speaker_mute, + &bitmap_icon_speaker, + Color::light_grey(), + Color::dark_grey(), + Color::green(), + Color::dark_grey()}; +}; + +} /* namespace ui */ + +#endif /*__UI_AUDIO_TEST_H__*/ diff --git a/firmware/application/external/external.cmake b/firmware/application/external/external.cmake index a84fa9319..120e58db4 100644 --- a/firmware/application/external/external.cmake +++ b/firmware/application/external/external.cmake @@ -73,6 +73,9 @@ set(EXTCPPSRC external/foxhunt/ui_foxhunt_rx.cpp external/foxhunt/ui_foxhunt_rx.hpp + #audio_test + external/audio_test/main.cpp + external/audio_test/ui_audio_test.cpp ) set(EXTAPPLIST @@ -93,4 +96,5 @@ set(EXTAPPLIST tetris extsensors foxhunt_rx + audio_test ) diff --git a/firmware/application/external/external.ld b/firmware/application/external/external.ld index c75276f39..4e3f12682 100644 --- a/firmware/application/external/external.ld +++ b/firmware/application/external/external.ld @@ -40,6 +40,7 @@ MEMORY ram_external_app_tetris(rwx) : org = 0xADBE0000, len = 32k ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k ram_external_app_foxhunt_rx(rwx) : org = 0xADC00000, len = 32k + ram_external_app_audio_test(rwx) : org = 0xADC10000, len = 32k } SECTIONS @@ -146,6 +147,10 @@ SECTIONS *(*ui*external_app*foxhunt_rx*); } > ram_external_app_foxhunt_rx - + .external_app_audio_test : ALIGN(4) SUBALIGN(4) + { + KEEP(*(.external_app.app_audio_test.application_information)); + *(*ui*external_app*audio_test*); + } > ram_external_app_audio_test } diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 99f4dca39..5751c0c2b 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -609,7 +609,6 @@ set(MODE_CPPSRC ) DeclareTargets(PNRR nrfrx) - ### Jammer set(MODE_CPPSRC @@ -645,6 +644,12 @@ set(MODE_CPPSRC ) DeclareTargets(PTST test) +### Audio Beep + +set(MODE_CPPSRC + proc_audio_beep.cpp +) +DeclareTargets(PABP audio_beep) ### HackRF "factory" firmware diff --git a/firmware/baseband/proc_audio_beep.cpp b/firmware/baseband/proc_audio_beep.cpp new file mode 100644 index 000000000..879612d40 --- /dev/null +++ b/firmware/baseband/proc_audio_beep.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "proc_audio_beep.hpp" +#include "event_m4.hpp" +#include "audio_dma.hpp" + +AudioBeepProcessor::AudioBeepProcessor() { +} + +void AudioBeepProcessor::execute(const buffer_c8_t& buffer) { + (void)buffer; +} + +void AudioBeepProcessor::on_message(const Message* const msg) { + switch (msg->id) { + case Message::ID::RequestSignal: + on_signal_message(*reinterpret_cast(msg)); + break; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(msg)); + break; + + default: + break; + } +} + +void AudioBeepProcessor::on_signal_message(const RequestSignalMessage& message) { + if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) { + audio::dma::beep_stop(); + } +} + +void AudioBeepProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, AUDIO_SAMPLE_RATE, message.duration_ms); +} + +int main() { + audio::dma::init_audio_out(); + EventDispatcher event_dispatcher{std::make_unique()}; + event_dispatcher.run(); + return 0; +} diff --git a/firmware/baseband/proc_audio_beep.hpp b/firmware/baseband/proc_audio_beep.hpp new file mode 100644 index 000000000..68166b910 --- /dev/null +++ b/firmware/baseband/proc_audio_beep.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PROC_AUDIO_BEEP_H__ +#define __PROC_AUDIO_BEEP_H__ + +#include "baseband_processor.hpp" +#include "message.hpp" + +#define AUDIO_SAMPLE_RATE 24000 + +class AudioBeepProcessor : public BasebandProcessor { + public: + AudioBeepProcessor(); + void execute(const buffer_c8_t& buffer) override; + void on_message(const Message* const msg); + + private: + void on_signal_message(const RequestSignalMessage& message); + void on_beep_message(const AudioBeepMessage& message); +}; + +#endif /*__PROC_AUDIO_BEEP_H__*/ diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index 9ee84fb65..0a95455cb 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -74,6 +74,7 @@ struct image_tag_t { }; constexpr image_tag_t image_tag_none{0, 0, 0, 0}; +constexpr image_tag_t image_tag_audio_beep{'P', 'A', 'B', 'P'}; 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'}; From 28a5fc5915fc2e923d53ab0ad8fe15ef9e0be203 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 23 Mar 2024 02:21:35 -0500 Subject: [PATCH 58/98] Improved Audio Beep Test (#2026) --- firmware/application/apps/ui_sonde.cpp | 2 +- firmware/application/baseband_api.cpp | 4 ++-- firmware/application/baseband_api.hpp | 2 +- .../external/audio_test/ui_audio_test.cpp | 20 ++++++++++++---- .../external/audio_test/ui_audio_test.hpp | 23 ++++++++++++------- firmware/baseband/proc_audio_beep.cpp | 2 +- firmware/baseband/proc_sonde.cpp | 4 ++-- firmware/baseband/proc_sonde.hpp | 2 +- firmware/baseband/tone_gen.cpp | 2 +- firmware/common/message.hpp | 3 +++ 10 files changed, 43 insertions(+), 21 deletions(-) diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 5b09af432..003d80858 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -75,7 +75,7 @@ SondeView::SondeView(NavigationView& nav) check_beep.on_select = [this](Checkbox&, bool v) { beep = v; if (beep) - baseband::request_audio_beep(1000, 60); // 1khz tone for 60ms to acknowledge enablement + baseband::request_audio_beep(1000, 24000, 60); // 1khz tone for 60ms to acknowledge enablement }; check_log.set_value(logging); diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 0095189da..e288d9d66 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -445,8 +445,8 @@ void request_beep_stop() { request_beep(RequestSignalMessage::Signal::BeepStopRequest); } -void request_audio_beep(uint32_t freq, uint32_t duration_ms) { - AudioBeepMessage message{freq, duration_ms}; +void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms) { + AudioBeepMessage message{freq, sample_rate, duration_ms}; send_message(&message); } diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 50e2282e8..a594fc273 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -93,7 +93,7 @@ void set_subghzd_config(uint8_t modulation, uint32_t sampling_rate); void request_roger_beep(); void request_rssi_beep(); void request_beep_stop(); -void request_audio_beep(uint32_t freq, uint32_t duration_ms); +void request_audio_beep(uint32_t freq, uint32_t sample_rate, uint32_t duration_ms); void run_image(const portapack::spi_flash::image_tag_t image_tag); void run_prepared_image(const uint32_t m4_code); diff --git a/firmware/application/external/audio_test/ui_audio_test.cpp b/firmware/application/external/audio_test/ui_audio_test.cpp index 66e00973c..2f0cb85fb 100644 --- a/firmware/application/external/audio_test/ui_audio_test.cpp +++ b/firmware/application/external/audio_test/ui_audio_test.cpp @@ -33,14 +33,26 @@ AudioTestView::AudioTestView(NavigationView& nav) baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too add_children({&labels, + &options_sample_rate, &field_frequency, &field_duration, &field_volume, &toggle_speaker}); + audio::set_rate(audio::Rate::Hz_24000); + options_sample_rate.on_change = [this](size_t, int32_t v) { + if (options_sample_rate.selected_index_value() == 24000) { + audio::set_rate(audio::Rate::Hz_24000); + field_frequency.set_range(100, v / 2); // 24000/128 = ~100 (audio_dma uses 128 samples) + } else { + audio::set_rate(audio::Rate::Hz_48000); + field_frequency.set_range(200, v / 2); // 48000/128 = ~200 + } + update_audio_beep(); + }; + field_frequency.set_value(1000); - field_frequency.on_change = [this](int32_t v) { - (void)v; + field_frequency.on_change = [this](int32_t) { update_audio_beep(); }; @@ -69,12 +81,12 @@ AudioTestView::~AudioTestView() { } void AudioTestView::focus() { - field_frequency.focus(); + toggle_speaker.focus(); } void AudioTestView::update_audio_beep() { if (beep) - baseband::request_audio_beep(field_frequency.value(), field_duration.value()); + baseband::request_audio_beep(field_frequency.value(), options_sample_rate.selected_index_value(), field_duration.value()); else baseband::request_beep_stop(); } diff --git a/firmware/application/external/audio_test/ui_audio_test.hpp b/firmware/application/external/audio_test/ui_audio_test.hpp index 34e36870c..6ad1bb932 100644 --- a/firmware/application/external/audio_test/ui_audio_test.hpp +++ b/firmware/application/external/audio_test/ui_audio_test.hpp @@ -45,20 +45,27 @@ class AudioTestView : public View { Labels labels{ {{7 * 8, 3 * 16}, "Audio Beep Test", Color::light_grey()}, - {{0 * 8, 6 * 16}, "Frequency (Hz):", Color::light_grey()}, - {{0 * 8, 8 * 16}, "Duration (ms):", Color::light_grey()}, - {{0 * 8, 10 * 16}, "Volume:", Color::light_grey()}}; + {{0 * 8, 6 * 16}, "Sample Rate (Hz):", Color::light_grey()}, + {{0 * 8, 8 * 16}, "Frequency (Hz):", Color::light_grey()}, + {{0 * 8, 10 * 16}, "Duration (ms):", Color::light_grey()}, + {{0 * 8, 12 * 16}, "Volume:", Color::light_grey()}}; + + OptionsField options_sample_rate{ + {18 * 8, 6 * 16}, + 5, + {{"24000", 24000}, + {"48000", 48000}}}; NumberField field_frequency{ - {16 * 8, 6 * 16}, + {18 * 8, 8 * 16}, 5, - {100, 24000}, + {100, 24000 / 2}, 100, ' ', true}; NumberField field_duration{ - {16 * 8, 8 * 16}, + {18 * 8, 10 * 16}, 5, {0, 60000}, 50, @@ -66,10 +73,10 @@ class AudioTestView : public View { true}; AudioVolumeField field_volume{ - {19 * 8, 10 * 16}}; + {21 * 8, 12 * 16}}; ImageToggle toggle_speaker{ - {19 * 8, 12 * 16, 2 * 8, 1 * 16}, + {21 * 8, 14 * 16, 2 * 8, 1 * 16}, &bitmap_icon_speaker_mute, &bitmap_icon_speaker, Color::light_grey(), diff --git a/firmware/baseband/proc_audio_beep.cpp b/firmware/baseband/proc_audio_beep.cpp index 879612d40..10fdc429d 100644 --- a/firmware/baseband/proc_audio_beep.cpp +++ b/firmware/baseband/proc_audio_beep.cpp @@ -52,7 +52,7 @@ void AudioBeepProcessor::on_signal_message(const RequestSignalMessage& message) } void AudioBeepProcessor::on_beep_message(const AudioBeepMessage& message) { - audio::dma::beep_start(message.freq, AUDIO_SAMPLE_RATE, message.duration_ms); + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); } int main() { diff --git a/firmware/baseband/proc_sonde.cpp b/firmware/baseband/proc_sonde.cpp index a40359d7d..b3e2ea47c 100644 --- a/firmware/baseband/proc_sonde.cpp +++ b/firmware/baseband/proc_sonde.cpp @@ -86,12 +86,12 @@ void SondeProcessor::on_signal_message(const RequestSignalMessage& message) { beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION; } - audio::dma::beep_start(beep_freq, AUDIO_SAMPLE_RATE, beep_duration); + audio::dma::beep_start(beep_freq, DEFAULT_AUDIO_SAMPLE_RATE, beep_duration); } } void SondeProcessor::on_beep_message(const AudioBeepMessage& message) { - audio::dma::beep_start(message.freq, AUDIO_SAMPLE_RATE, message.duration_ms); + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); } void SondeProcessor::on_pitch_rssi_config(const PitchRSSIConfigureMessage& message) { diff --git a/firmware/baseband/proc_sonde.hpp b/firmware/baseband/proc_sonde.hpp index 7b6784139..3496976d5 100644 --- a/firmware/baseband/proc_sonde.hpp +++ b/firmware/baseband/proc_sonde.hpp @@ -103,7 +103,7 @@ #define RSSI_CEILING 1000 #define PROPORTIONAL_BEEP_THRES 0.8 #define RSSI_PITCH_WEIGHT (float(BEEP_MAX_FREQ - BEEP_BASE_FREQ) / RSSI_CEILING) -#define AUDIO_SAMPLE_RATE 24000 +#define DEFAULT_AUDIO_SAMPLE_RATE 24000 class SondeProcessor : public BasebandProcessor { public: diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index efe74c66d..485824278 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -27,7 +27,7 @@ // Functions for audio beep (used by Sonde RSSI) void ToneGen::configure_beep(const uint32_t freq, const uint32_t sample_rate) { f_delta_ = (float)(freq * sizeof(sine_table_i8)) / sample_rate; - f_tone_phase_ = 0.0; + f_tone_phase_ = sizeof(sine_table_i8) / 4; // Start at sine peak to handle case of freq=sample_rate/2 } int16_t ToneGen::process_beep() { diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 1bf4e12da..c6f2718a5 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -1368,12 +1368,15 @@ class AudioBeepMessage : public Message { public: constexpr AudioBeepMessage( uint32_t freq = 1000, + uint32_t sample_rate = 24000, uint32_t duration_ms = 100) : Message{ID::AudioBeep}, freq{freq}, + sample_rate{sample_rate}, duration_ms{duration_ms} { } uint32_t freq = 1000; + uint32_t sample_rate = 24000; uint32_t duration_ms = 100; }; #endif /*__MESSAGE_H__*/ From 81e24d582d1ecf3eb56d1ce29d3a55666a933203 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 23 Mar 2024 13:25:36 -0500 Subject: [PATCH 59/98] More debug Audio Beep Test tweaks (#2028) --- .../external/audio_test/ui_audio_test.cpp | 30 +++++++++++++------ .../external/audio_test/ui_audio_test.hpp | 15 ++++++++-- firmware/baseband/tone_gen.cpp | 8 ++++- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/firmware/application/external/audio_test/ui_audio_test.cpp b/firmware/application/external/audio_test/ui_audio_test.cpp index 2f0cb85fb..de1387648 100644 --- a/firmware/application/external/audio_test/ui_audio_test.cpp +++ b/firmware/application/external/audio_test/ui_audio_test.cpp @@ -35,39 +35,51 @@ AudioTestView::AudioTestView(NavigationView& nav) add_children({&labels, &options_sample_rate, &field_frequency, + &options_step, &field_duration, &field_volume, &toggle_speaker}); audio::set_rate(audio::Rate::Hz_24000); options_sample_rate.on_change = [this](size_t, int32_t v) { - if (options_sample_rate.selected_index_value() == 24000) { - audio::set_rate(audio::Rate::Hz_24000); - field_frequency.set_range(100, v / 2); // 24000/128 = ~100 (audio_dma uses 128 samples) - } else { - audio::set_rate(audio::Rate::Hz_48000); - field_frequency.set_range(200, v / 2); // 48000/128 = ~200 + switch (v) { + case 12000: + audio::set_rate(audio::Rate::Hz_12000); + break; + case 24000: + audio::set_rate(audio::Rate::Hz_24000); + break; + case 48000: + audio::set_rate(audio::Rate::Hz_48000); + break; } + field_frequency.set_range(v / 128, v / 2); update_audio_beep(); }; + options_sample_rate.set_selected_index(0, 1); - field_frequency.set_value(1000); field_frequency.on_change = [this](int32_t) { update_audio_beep(); }; + field_frequency.set_value(1000); + + options_step.on_change = [this](size_t, int32_t v) { + field_frequency.set_step(v); + }; + options_step.set_by_value(100); - field_duration.set_value(100); field_duration.on_change = [this](int32_t v) { (void)v; update_audio_beep(); }; + field_duration.set_value(100); toggle_speaker.on_change = [this](bool v) { beep = v; update_audio_beep(); }; - field_volume.set_value(0); + field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first field_volume.set_value(80); audio::set_rate(audio::Rate::Hz_24000); diff --git a/firmware/application/external/audio_test/ui_audio_test.hpp b/firmware/application/external/audio_test/ui_audio_test.hpp index 6ad1bb932..7e5f9c91d 100644 --- a/firmware/application/external/audio_test/ui_audio_test.hpp +++ b/firmware/application/external/audio_test/ui_audio_test.hpp @@ -46,20 +46,31 @@ class AudioTestView : public View { Labels labels{ {{7 * 8, 3 * 16}, "Audio Beep Test", Color::light_grey()}, {{0 * 8, 6 * 16}, "Sample Rate (Hz):", Color::light_grey()}, + {{25 * 8, 7 * 16}, "Step:", Color::light_grey()}, {{0 * 8, 8 * 16}, "Frequency (Hz):", Color::light_grey()}, {{0 * 8, 10 * 16}, "Duration (ms):", Color::light_grey()}, + {{25 * 8, 10 * 16}, "0=con", Color::light_grey()}, {{0 * 8, 12 * 16}, "Volume:", Color::light_grey()}}; OptionsField options_sample_rate{ {18 * 8, 6 * 16}, 5, {{"24000", 24000}, - {"48000", 48000}}}; + {"48000", 48000}, + {"12000", 12000}}}; + + OptionsField options_step{ + {26 * 8, 8 * 16}, + 4, + {{" 1", 1}, + {" 10", 10}, + {" 100", 100}, + {"1000", 1000}}}; NumberField field_frequency{ {18 * 8, 8 * 16}, 5, - {100, 24000 / 2}, + {}, 100, ' ', true}; diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index 485824278..10ec1b819 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -27,7 +27,13 @@ // Functions for audio beep (used by Sonde RSSI) void ToneGen::configure_beep(const uint32_t freq, const uint32_t sample_rate) { f_delta_ = (float)(freq * sizeof(sine_table_i8)) / sample_rate; - f_tone_phase_ = sizeof(sine_table_i8) / 4; // Start at sine peak to handle case of freq=sample_rate/2 + f_tone_phase_ = 0.0; + + // For higher frequencies, start at sine peak to handle case of freq=sample_rate/2; + // we don't want to sample the sine wave only when it's crossing 0! + // There is still an amplitude issue though depending on magnitude of selected sine sample deltas. + if (f_delta_ >= sizeof(sine_table_i8) / 4) + f_tone_phase_ = sizeof(sine_table_i8) / 4; } int16_t ToneGen::process_beep() { From 1a87f2d701a2b213121e02b5b92cc7700a5d7263 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 23 Mar 2024 13:26:46 -0500 Subject: [PATCH 60/98] Revert accidental newbutton bg color change (#2029) --- firmware/application/apps/ui_fileman.cpp | 2 +- firmware/application/apps/ui_fileman.hpp | 8 ++++---- firmware/common/ui_widget.hpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 35e4c5e18..9d33be043 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -694,7 +694,7 @@ FileManagerView::FileManagerView( button_show_hidden_files.on_select = [this]() { show_hidden_files = !show_hidden_files; - button_show_hidden_files.set_color(show_hidden_files ? Color::dark_green() : Color::dark_grey()); + button_show_hidden_files.set_color(show_hidden_files ? Color::green() : Color::dark_grey()); reload_current(); }; } diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 83a8cda8a..06ee942c6 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -261,19 +261,19 @@ class FileManagerView : public FileManBaseView { {22 * 8, 29 * 8, 4 * 8, 32}, {}, &bitmap_icon_new_dir, - Color::dark_green()}; + Color::green()}; NewButton button_new_file{ {26 * 8, 29 * 8, 4 * 8, 32}, {}, &bitmap_icon_new_file, - Color::dark_green()}; + Color::green()}; NewButton button_open_notepad{ {0 * 8, 34 * 8, 4 * 8, 32}, {}, &bitmap_icon_notepad, - Color::dark_orange()}; + Color::orange()}; NewButton button_rename_timestamp{ @@ -288,7 +288,7 @@ class FileManagerView : public FileManBaseView { {4 * 8, 34 * 8, 4 * 8, 32}, {}, &bitmap_icon_trim, - Color::dark_orange()}; + Color::orange()}; NewButton button_show_hidden_files{ {17 * 8, 34 * 8, 4 * 8, 32}, diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index f0109d1cc..63f0e2955 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -523,7 +523,7 @@ class NewButton : public Widget { protected: virtual Style paint_style(); Color color_; - Color bg_color_{Color::light_grey()}; + Color bg_color_{Color::grey()}; private: std::string text_; From 536981998b2e302a010c5dec091e1fcc2cf08fc7 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sat, 23 Mar 2024 19:27:05 +0100 Subject: [PATCH 61/98] Level fix and beep, RSSI avg fix (#2027) * fix average value being overflow'd * fix audio and mod changes, preps for beep mode * fixed beep_freq range, added a stop and set a variable sooner * added support for audio beep messages * better scaler for beep * added bip squelch and saving of bip squelch and audio mode * saving modulation, fixing audio * added save and restore of bandwidth * simpler ctcss clean on change mode --- firmware/application/apps/ui_level.cpp | 111 +++++++++++++++++++------ firmware/application/apps/ui_level.hpp | 55 ++++++++---- firmware/baseband/proc_capture.cpp | 23 ++++- firmware/baseband/proc_capture.hpp | 4 + firmware/common/message.hpp | 2 +- 5 files changed, 149 insertions(+), 46 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 278e57620..82d18a3f5 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -35,6 +35,25 @@ using portapack::memory::map::backup_ram; namespace ui { +void LevelView::m4_manage_stat_update() { + if (audio_mode) { + if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) { + shared_memory.request_m4_performance_counter = 0; + } else { + shared_memory.request_m4_performance_counter = 2; + } + if (radio_mode == SPEC_MODULATION) { + beep = true; + } + } else { + shared_memory.request_m4_performance_counter = 2; + if (radio_mode == SPEC_MODULATION) { + beep = false; + baseband::request_beep_stop(); + } + } +} + void LevelView::focus() { button_frequency.focus(); } @@ -62,18 +81,15 @@ LevelView::LevelView(NavigationView& nav) &freq_stats_rssi, &freq_stats_db, &freq_stats_rx, - &audio_mode, + &text_beep_squelch, + &field_beep_squelch, + &field_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 freq_ = receiver_model.target_frequency(); button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>"); @@ -87,6 +103,11 @@ LevelView::LevelView(NavigationView& nav) }; }; + field_beep_squelch.set_value(beep_squelch); + field_beep_squelch.on_change = [this](int32_t v) { + beep_squelch = v; + }; + button_frequency.on_change = [this]() { int64_t def_step = freqman_entry_get_step_value(step_mode.selected_index()); freq_ = freq_ + (button_frequency.get_encoder_delta() * def_step); @@ -102,17 +123,14 @@ LevelView::LevelView(NavigationView& nav) button_frequency.set_text("<" + to_string_short_freq(freq_) + " MHz>"); }; + freqman_set_modulation_option(field_mode); field_mode.on_change = [this](size_t, OptionsField::value_t v) { if (v != -1) { - receiver_model.disable(); - baseband::shutdown(); change_mode(v); - if (audio_mode.selected_index() != 0) { - audio::output::start(); - } - receiver_model.enable(); } }; + field_mode.set_by_value(radio_mode); // Reflect the mode into the manual selector + field_bw.set_selected_index(radio_bw); rssi_resolution.on_change = [this](size_t, OptionsField::value_t v) { if (v != -1) { @@ -120,15 +138,18 @@ LevelView::LevelView(NavigationView& nav) } }; - audio_mode.on_change = [this](size_t, OptionsField::value_t v) { + field_audio_mode.on_change = [this](size_t, OptionsField::value_t v) { + audio_mode = v; if (v == 0) { audio::output::stop(); } else if (v == 1) { + audio::set_rate(audio_sampling_rate); audio::output::start(); receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. - } else { } + m4_manage_stat_update(); // rx_sat hack }; + field_audio_mode.set_selected_index(audio_mode); peak_mode.on_change = [this](size_t, OptionsField::value_t v) { if (v == 0) { @@ -142,7 +163,6 @@ LevelView::LevelView(NavigationView& nav) peak_mode.set_selected_index(2); rssi_resolution.set_selected_index(1); // FILL STEP OPTIONS - freqman_set_modulation_option(field_mode); freqman_set_step_option_short(step_mode); freq_stats_rssi.set_style(&Styles::white); freq_stats_db.set_style(&Styles::white); @@ -168,13 +188,28 @@ 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_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())); + freq_stats_rssi.set("RSSI: " + to_string_dec_uint(last_min_rssi) + "/" + to_string_dec_uint(last_avg_rssi) + "/" + to_string_dec_uint(last_max_rssi)); } + + if (beep && statistics.max_db > beep_squelch) { + baseband::request_audio_beep(((132 + statistics.max_db) * 2000) / 120, 24000, 250); + } + // refresh sat + if (radio_mode == SPEC_MODULATION || (radio_mode == WFM_MODULATION && audio_mode == 1)) { + Style style_freq_stats_rx{ + .font = font::fixed_8x16, + .background = {55, 55, 55}, + .foreground = {155, 155, 155}, + }; + freq_stats_rx.set_style(&style_freq_stats_rx); + freq_stats_rx.set("RxSat off"); + return; + } 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; @@ -191,6 +226,7 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { .foreground = {255, 255, 255}, }; freq_stats_rx.set_style(&style_freq_stats_rx); + freq_stats_rx.set("RxSat: " + to_string_dec_uint(rx_sat) + "%"); } } /* on_statistic_updates */ @@ -198,50 +234,59 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { size_t LevelView::change_mode(freqman_index_t new_mod) { field_bw.on_change = [this](size_t n, OptionsField::value_t) { (void)n; }; + radio_mode = new_mod; + + audio::output::stop(); + receiver_model.disable(); + baseband::shutdown(); + switch (new_mod) { case AM_MODULATION: + audio_sampling_rate = audio::Rate::Hz_12000; freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_am_audio); receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); - receiver_model.set_am_configuration(field_bw.selected_index_value()); - field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); }; // bw DSB (0) default field_bw.set_by_value(0); - text_ctcss.set(" "); + receiver_model.set_am_configuration(0); + field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_am_configuration(n); }; break; case NFM_MODULATION: + audio_sampling_rate = audio::Rate::Hz_24000; freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_nbfm_configuration(field_bw.selected_index_value()); - field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); }; // bw 16k (2) default field_bw.set_by_value(2); + field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_nbfm_configuration(n); }; break; case WFM_MODULATION: + audio_sampling_rate = audio::Rate::Hz_48000; freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_wfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio); receiver_model.set_wfm_configuration(field_bw.selected_index_value()); - field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); }; - // bw 200k (0) only/default + // bw 200k (0) default field_bw.set_by_value(0); - text_ctcss.set(" "); + field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); }; break; case SPEC_MODULATION: + audio_sampling_rate = audio::Rate::Hz_24000; freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_capture); receiver_model.set_modulation(ReceiverModel::Mode::Capture); - field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) { + // 12k5 (0) default + field_bw.set_by_value(0); + field_bw.on_change = [this](size_t index, OptionsField::value_t sampling_rate) { + radio_bw = index; // Baseband needs to know the desired sampling and oversampling rates. baseband::set_sample_rate(sampling_rate, get_oversample_rate(sampling_rate)); - // The radio needs to know the effective sampling rate. auto actual_sampling_rate = get_actual_sample_rate(sampling_rate); receiver_model.set_sampling_rate(actual_sampling_rate); receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate)); }; - field_bw.set_by_value(0); default: break; } @@ -250,6 +295,18 @@ size_t LevelView::change_mode(freqman_index_t new_mod) { receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); } + if (new_mod != NFM_MODULATION) { + text_ctcss.set(" "); + } + + m4_manage_stat_update(); // rx_sat hack + + if (audio_mode) { + audio::set_rate(audio_sampling_rate); + audio::output::start(); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. + } + receiver_model.enable(); return step_mode.selected_index(); } diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 0f9681e84..86862a6cd 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -55,14 +55,29 @@ class LevelView : public View { NavigationView& nav_; RxRadioState radio_state_{}; - app_settings::SettingsManager settings_{ - "rx_level", app_settings::Mode::RX}; size_t change_mode(freqman_index_t mod_type); void on_statistics_update(const ChannelStatistics& statistics); void set_display_freq(int64_t freq); + void m4_manage_stat_update(); // to finely adjust the RxSaturation usage rf::Frequency freq_ = {0}; + bool beep = false; + uint8_t radio_mode = 0; + uint8_t radio_bw = 0; + uint8_t audio_mode = 0; + int32_t beep_squelch = 0; + audio::Rate audio_sampling_rate = audio::Rate::Hz_48000; + + app_settings::SettingsManager settings_{ + "rx_level", + app_settings::Mode::RX, + { + {"beep_squelch"sv, &beep_squelch}, + {"audio_mode"sv, &audio_mode}, + {"radio_mode"sv, &radio_mode}, + {"radio_bw"sv, &radio_bw}, + }}; Labels labels{ {{0 * 8, 0 * 16}, "LNA: VGA: AMP: VOL: ", Color::light_grey()}, @@ -100,23 +115,27 @@ class LevelView : public View { {0 * 8, 2 * 16 + 8, 15 * 8, 1 * 8}, ""}; - OptionsField audio_mode{ + OptionsField field_audio_mode{ {21 * 8, 1 * 16}, 9, - { - {"audio off", 0}, - {"audio on", 1} - //{"tone on", 2}, - //{"tone off", 3}, - }}; + {{"audio off", 0}, + {"audio on", 1}}}; - Text text_ctcss{ - {22 * 8, 3 * 16 + 4, 8 * 8, 1 * 8}, - ""}; + Text text_beep_squelch{ + {21 * 8, 3 * 16 + 4, 4 * 8, 1 * 8}, + "Bip>"}; - // RSSI: XX/XX/XXX,dt: XX + NumberField field_beep_squelch{ + {25 * 8, 3 * 16 + 4}, + 3, + {-120, 12}, + 1, + ' ', + }; + + // RSSI: XX/XX/XXX Text freq_stats_rssi{ - {0 * 8, 3 * 16 + 4, 22 * 8, 1 * 16}, + {0 * 8, 3 * 16 + 4, 15 * 8, 1 * 16}, }; // Power: -XXX db @@ -153,14 +172,18 @@ class LevelView : public View { {0 * 8, 5 * 16 + 4, 10 * 8, 1 * 16}, }; + Text text_ctcss{ + {12 * 8, 5 * 16 + 4, 8 * 8, 1 * 8}, + ""}; + RSSIGraph rssi_graph{ // 240x320 => - {0, 6 * 16 + 4, 240 - 5 * 8, 320 - (6 * 16 + 4)}, + {0, 6 * 16 + 8, 240 - 5 * 8, 320 - (6 * 16)}, }; RSSI rssi{ // 240x320 => - {240 - 5 * 8, 6 * 16 + 4, 5 * 8, 320 - (6 * 16 + 4)}, + {240 - 5 * 8, 6 * 16 + 8, 5 * 8, 320 - (6 * 16)}, }; void handle_coded_squelch(const uint32_t value); diff --git a/firmware/baseband/proc_capture.cpp b/firmware/baseband/proc_capture.cpp index c29255f1c..a9f585cbd 100644 --- a/firmware/baseband/proc_capture.cpp +++ b/firmware/baseband/proc_capture.cpp @@ -21,7 +21,7 @@ */ #include "proc_capture.hpp" - +#include "audio_dma.hpp" #include "dsp_fir_taps.hpp" #include "event_m4.hpp" #include "utility.hpp" @@ -55,6 +55,16 @@ void CaptureProcessor::execute(const buffer_c8_t& buffer) { } } +void CaptureProcessor::on_signal_message(const RequestSignalMessage& message) { + if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) { + audio::dma::beep_stop(); + } +} + +void CaptureProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + void CaptureProcessor::on_message(const Message* const message) { switch (message->id) { case Message::ID::UpdateSpectrum: @@ -70,6 +80,14 @@ void CaptureProcessor::on_message(const Message* const message) { capture_config(*reinterpret_cast(message)); break; + case Message::ID::RequestSignal: + on_signal_message(*reinterpret_cast(message)); + break; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(message)); + break; + default: break; } @@ -152,7 +170,8 @@ void CaptureProcessor::capture_config(const CaptureConfigMessage& message) { } int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; -} \ No newline at end of file +} diff --git a/firmware/baseband/proc_capture.hpp b/firmware/baseband/proc_capture.hpp index de51e23cf..7df220d23 100644 --- a/firmware/baseband/proc_capture.hpp +++ b/firmware/baseband/proc_capture.hpp @@ -30,6 +30,7 @@ #include "dsp_decimate.hpp" #include "spectrum_collector.hpp" #include "stream_input.hpp" +#include "message.hpp" #include #include @@ -92,6 +93,9 @@ class CaptureProcessor : public BasebandProcessor { void on_message(const Message* const message) override; private: + void on_signal_message(const RequestSignalMessage& message); + void on_beep_message(const AudioBeepMessage& message); + size_t baseband_fs = 3072000; // aka: sample_rate static constexpr auto spectrum_rate_hz = 50.0f; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index c6f2718a5..e116aa3f2 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -134,7 +134,7 @@ class Message { }; struct RSSIStatistics { - uint16_t accumulator{0}; + uint32_t accumulator{0}; uint8_t min{0}; uint8_t max{0}; uint16_t count{0}; From 6e2507d609fc6fb5381296d0b3f46bd6699c269c Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:01:48 +0100 Subject: [PATCH 62/98] fix gui glitch on beep squelch (#2030) --- firmware/application/apps/ui_level.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 86862a6cd..51bfc5c69 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -127,7 +127,7 @@ class LevelView : public View { NumberField field_beep_squelch{ {25 * 8, 3 * 16 + 4}, - 3, + 4, {-120, 12}, 1, ' ', From abb9b6c8ad0a226b83dd3499c90abc88cfaf7b22 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 23 Mar 2024 15:34:15 -0500 Subject: [PATCH 63/98] Add make dependency on baseband for external APPS (#2031) --- firmware/application/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 575c50322..2e56b93f5 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -505,7 +505,7 @@ add_custom_command( OUTPUT ${PROJECT_NAME}.bin COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin --remove-section=.external_app_* COMMAND ${EXPORT_EXTERNAL_APP_IMAGES} ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_OBJCOPY} ${EXTAPPLIST} - DEPENDS ${PROJECT_NAME}.elf + DEPENDS ${PROJECT_NAME}.elf ${baseband_BINARY_DIR}/baseband.img ) add_custom_target( From 4c012a9493b49d34e1a75a92d1c6ac09c05e8d8c Mon Sep 17 00:00:00 2001 From: ImDroided Date: Sat, 23 Mar 2024 21:16:27 -0500 Subject: [PATCH 64/98] Added and fixed freqs (#2033) Figured I would clean these up and add a bit. --- sdcard/FREQMAN/CHIPD.TXT | 11 ++++++----- sdcard/LOOKINGGLASS/PRESETS.TXT | 28 +++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/sdcard/FREQMAN/CHIPD.TXT b/sdcard/FREQMAN/CHIPD.TXT index 5f94f3b73..6759850a6 100644 --- a/sdcard/FREQMAN/CHIPD.TXT +++ b/sdcard/FREQMAN/CHIPD.TXT @@ -1,5 +1,6 @@ -f=460125000,d=CPDCW1 CH1 -f=460175000,d=CPDCW2 CH2 -f=460275000,d=CPDCW3 CH3 -f=460325000,d=CPDCW4 CH4 -f=460350000,d=CPDCW5 CH5 +# Chicago Police City Wide Dispatch +f=460125000,d=Chicago PD CW1 +f=460175000,d=Chicago PD CW2 +f=460275000,d=Chicago PD CW3 +f=460325000,d=Chicago PD CW4 +f=460350000,d=Chicago PD CW5 diff --git a/sdcard/LOOKINGGLASS/PRESETS.TXT b/sdcard/LOOKINGGLASS/PRESETS.TXT index 92c353b02..4fbf7062b 100644 --- a/sdcard/LOOKINGGLASS/PRESETS.TXT +++ b/sdcard/LOOKINGGLASS/PRESETS.TXT @@ -5,13 +5,22 @@ # 433 MHz BAND 423,443,433 BAND # AVIATION -108,137,AVIATION 108 +108,118,AVIATION 108 NAVAIDS +118,137,AVIATION 118 VOICE 960,1215,AVIATION 960 +1089,1091,ADS-B 1090 +128,137,ACARS # BROADCAST RADIO -87,108,FM BROADCAST +87,108,FM BROADCAST USA 76,108,FM BROADCAST BRAZIL 76,95,FM BROADCAST JAPAN 65,74,FM BROADCAST RUSSIA +# CITIZENS BAND RADIO +26,28,CITIZENS BAND RADIO +# COMMON PUBLIC SERVICE BANDS +150,160, PUBLIC SERVICE 155 +450,470,PUBLIC SERVICE 460 +769,775,PUBLIC SERVICE 770 # DECT 1879,1931,DECT # FRS/GMRS @@ -25,7 +34,12 @@ 902,928,HAM 33-CM 1240,1300,HAM 23-CM # KEYFOBS -260,500,315/433 MHz KEYFOBS +305,325,315 MHz KEYFOBS +380,400,390 MHz KEYFOBS +423,443,433 MHz KEYFOBS +858,878,868 MHz KEYFOBS +902,929,915 MHz KEYFOBS +# 260,500,315/433 MHz KEYFOBS # LoRa 433,435,LoRa 443EU 863,870,LoRa 868EU @@ -36,14 +50,22 @@ # MICS 140,380,MICS (VHF) AND MARINE 420,660,MICS (UHF) +169,172,MICS COMMON +# MULTI-USE RADIO SERVICE - MURS +151,155,MULTI-USE RADIO SRVS +# NOAA WEATHER RADIO +161,164,NOAA WEATHER RADIO # PAGERS https://www.fcc.gov/wireless/bureau-divisions/mobility-division/paging 34,36,USA PAGERS 35 43,45,USA PAGERS 44 151,153,USA PAGERS 152 +157,159,USA PAGERS 158 453,454,USA PAGERS 454 929,931,USA PAGERS 930 # RADIOSONDES 390,420,RADIOSONDES +# RAILROAD +159,162,RAILROAD # WATER METERS 850,900,Water meters 902,928,ISM 900MHz From 53a1bacd46787003cdbb374f433acd65020c17ff Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:39:20 -0500 Subject: [PATCH 65/98] Revert "Add cmake dependency on baseband for external APPS" (#2034) This reverts commit abb9b6c8ad0a226b83dd3499c90abc88cfaf7b22. --- firmware/application/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 2e56b93f5..575c50322 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -505,7 +505,7 @@ add_custom_command( OUTPUT ${PROJECT_NAME}.bin COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin --remove-section=.external_app_* COMMAND ${EXPORT_EXTERNAL_APP_IMAGES} ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_OBJCOPY} ${EXTAPPLIST} - DEPENDS ${PROJECT_NAME}.elf ${baseband_BINARY_DIR}/baseband.img + DEPENDS ${PROJECT_NAME}.elf ) add_custom_target( From 6177b08632fdd9fa2cd24b55500d0557cd6b9598 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 24 Mar 2024 11:47:15 +0100 Subject: [PATCH 66/98] fixing level beep, bad copy paste on special SPEC mode (#2035) Co-authored-by: gullradriel --- firmware/application/apps/ui_level.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 82d18a3f5..3922d9d07 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -38,7 +38,7 @@ namespace ui { void LevelView::m4_manage_stat_update() { if (audio_mode) { if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) { - shared_memory.request_m4_performance_counter = 0; + shared_memory.request_m4_performance_counter = 1; } else { shared_memory.request_m4_performance_counter = 2; } @@ -277,7 +277,6 @@ size_t LevelView::change_mode(freqman_index_t new_mod) { baseband::run_image(portapack::spi_flash::image_tag_capture); receiver_model.set_modulation(ReceiverModel::Mode::Capture); // 12k5 (0) default - field_bw.set_by_value(0); field_bw.on_change = [this](size_t index, OptionsField::value_t sampling_rate) { radio_bw = index; // Baseband needs to know the desired sampling and oversampling rates. @@ -287,6 +286,7 @@ size_t LevelView::change_mode(freqman_index_t new_mod) { receiver_model.set_sampling_rate(actual_sampling_rate); receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate)); }; + field_bw.set_by_value(0); default: break; } From c078bac0e7d3e2ed6e61ce167a54bc01b849fda6 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sun, 24 Mar 2024 22:32:13 +0100 Subject: [PATCH 67/98] Looking glass beep (#2036) * first draft of looking beep * fixed beep squelch range in percent * took out steps * gui adjustements * uniformize calculation and beep squelch in db * uniformisation, fix 24/48 error --- firmware/application/apps/ui_level.cpp | 7 +- firmware/application/apps/ui_level.hpp | 3 +- .../application/apps/ui_looking_glass_app.cpp | 71 +++++++++++++++++-- .../application/apps/ui_looking_glass_app.hpp | 25 +++++-- firmware/baseband/proc_wideband_spectrum.cpp | 24 ++++++- firmware/baseband/proc_wideband_spectrum.hpp | 3 + 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 3922d9d07..62bf68658 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -35,6 +35,11 @@ using portapack::memory::map::backup_ram; namespace ui { +// Function to map the value from one range to another +int32_t LevelView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) { + return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow); +} + void LevelView::m4_manage_stat_update() { if (audio_mode) { if (radio_mode == WFM_MODULATION || radio_mode == SPEC_MODULATION) { @@ -192,7 +197,7 @@ void LevelView::on_statistics_update(const ChannelStatistics& statistics) { } if (beep && statistics.max_db > beep_squelch) { - baseband::request_audio_beep(((132 + statistics.max_db) * 2000) / 120, 24000, 250); + baseband::request_audio_beep(map(statistics.max_db, -100, 20, 400, 2600), 24000, 150); } // refresh sat diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index 51bfc5c69..3ce79bfa6 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -56,6 +56,7 @@ class LevelView : public View { RxRadioState radio_state_{}; + int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh); size_t change_mode(freqman_index_t mod_type); void on_statistics_update(const ChannelStatistics& statistics); void set_display_freq(int64_t freq); @@ -128,7 +129,7 @@ class LevelView : public View { NumberField field_beep_squelch{ {25 * 8, 3 * 16 + 4}, 4, - {-120, 12}, + {-100, 20}, 1, ' ', }; diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 62a2b03a6..0f2f8aa86 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -25,6 +25,7 @@ #include "convert.hpp" #include "file_reader.hpp" #include "string_format.hpp" +#include "audio.hpp" using namespace portapack; @@ -34,11 +35,39 @@ void GlassView::focus() { } GlassView::~GlassView() { + audio::output::stop(); receiver_model.set_sampling_rate(3072000); // Just a hack to avoid hanging other apps receiver_model.disable(); baseband::shutdown(); } +// Function to map the value from one range to another +int32_t GlassView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh) { + return toLow + (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow); +} + +void GlassView::update_display_beep() { + if (beep_enabled) { + button_beep_squelch.set_style(&Styles::green); + // + button_beep_squelch.set_text("[bip>" + to_string_dec_int(beep_squelch, 4) + "db]"); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. + } else { + button_beep_squelch.set_style(&Styles::white); + button_beep_squelch.set_text("[ beep OFF ["); + } +} + +void GlassView::manage_beep_audio() { + if (beep_enabled) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } else { + baseband::request_beep_stop(); + audio::output::stop(); + } +} + void GlassView::get_max_power(const ChannelSpectrum& spectrum, uint8_t bin, uint8_t& max_power) { if (mode == LOOKING_GLASS_SINGLEPASS) { // <20MHz spectrum mode @@ -173,6 +202,8 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) { // we actually need SCREEN_W (240) of those bins for (uint8_t bin = 0; bin < bin_length; bin++) { get_max_power(spectrum, bin, max_power); + if (max_power > range_max_power) + range_max_power = max_power; // process dc spike if enable if (bin == 119) { uint8_t next_max_power = 0; @@ -184,14 +215,21 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum& spectrum) { } } // process actual bin - if (process_bins(&max_power) == true) + if (process_bins(&max_power)) { + int8_t power = map(range_max_power, 0, 255, -100, 20); + if (power >= beep_squelch) { + baseband::request_audio_beep(map(range_max_power, 0, 256, 400, 2600), 24000, 250); + } + range_max_power = 0; return; // new line signaled, return + } } if (mode != LOOKING_GLASS_SINGLEPASS) { f_center += looking_glass_step; retune(); - } else + } else { baseband::spectrum_streaming_start(); + } } void GlassView::on_hide() { @@ -327,13 +365,15 @@ GlassView::GlassView( &field_lna, &field_vga, &field_range, - &steps_config, + //&steps_config, &scan_type, &view_config, &level_integration, + &field_volume, &filter_config, &field_rf_amp, &range_presets, + &button_beep_squelch, &field_marker, &field_trigger, &button_jump, @@ -370,12 +410,12 @@ GlassView::GlassView( }; }; - steps_config.on_change = [this](size_t, OptionsField::value_t v) { + /*steps_config.on_change = [this](size_t, OptionsField::value_t v) { field_frequency_min.set_step(v); field_frequency_max.set_step(v); steps = v; }; - steps_config.set_selected_index(0); // 1 Mhz step. + steps_config.set_selected_index(0); // 1 Mhz step.*/ scan_type.on_change = [this](size_t, OptionsField::value_t v) { mode = v; @@ -497,6 +537,27 @@ GlassView::GlassView( receiver_model.set_baseband_bandwidth(looking_glass_bandwidth); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz receiver_model.set_squelch_level(0); receiver_model.enable(); + + button_beep_squelch.on_select = [this](ButtonWithEncoder& button) { + (void)button; + beep_enabled = 1 - beep_enabled; + manage_beep_audio(); + update_display_beep(); + }; + + button_beep_squelch.on_change = [this]() { + int new_beep_squelch = beep_squelch + button_beep_squelch.get_encoder_delta(); + if (new_beep_squelch < -100) + new_beep_squelch = -100; + if (new_beep_squelch > 20) + new_beep_squelch = 20; + beep_squelch = new_beep_squelch; + button_beep_squelch.set_encoder_delta(0); + update_display_beep(); + }; + + manage_beep_audio(); + update_display_beep(); } uint8_t GlassView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read & write real iq_phase_calibration_value diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index d3052c6fe..a19dd1e99 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -85,6 +85,8 @@ class GlassView : public View { 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 + int32_t beep_squelch = 20; // range from -100 to +20, >=20 disabled + bool beep_enabled = false; // activate on bip button click app_settings::SettingsManager settings_{ "rx_glass"sv, app_settings::Mode::RX, @@ -98,6 +100,8 @@ class GlassView : public View { {"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. + {"beep_squelch"sv, &beep_squelch}, + {"beep_enabled"sv, &beep_enabled}, }}; struct preset_entry { @@ -106,7 +110,10 @@ class GlassView : public View { std::string label{}; }; + int32_t map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t toLow, int32_t toHigh); std::vector presets_db{}; + void manage_beep_audio(); + void update_display_beep(); void update_min(int32_t v); void update_max(int32_t v); void update_range_field(); @@ -153,6 +160,8 @@ class GlassView : public View { int32_t steps = 1; bool locked_range = false; + uint8_t range_max_power = 0; + uint8_t range_max_power_counter = 0; uint8_t max_power = 0; rf::Frequency max_freq_hold = 0; rf::Frequency last_max_freq = 0; @@ -166,7 +175,8 @@ class GlassView : public View { {{0, 1 * 16}, "RANGE: FILTER: AMP:", Color::light_grey()}, {{0, 2 * 16}, "PRESET:", Color::light_grey()}, {{0, 3 * 16}, "MARKER: MHz RXIQCAL", Color::light_grey()}, - {{0, 4 * 16}, "RES: STEP:", Color::light_grey()}}; + //{{0, 4 * 16}, "RES: STEPS:", Color::light_grey()}}; + {{0, 4 * 16}, "RES: VOL:", Color::light_grey()}}; NumberField field_frequency_min{ {4 * 8, 0 * 16}, @@ -206,9 +216,13 @@ class GlassView : public View { OptionsField range_presets{ {7 * 8, 2 * 16}, - 20, + 10, {}}; + ButtonWithEncoder button_beep_squelch{ + {18 * 8, 2 * 16 + 4, 12 * 8, 1 * 8}, + ""}; + TextField field_marker{ {7 * 8, 3 * 16, 9 * 8, 16}, ""}; @@ -228,7 +242,10 @@ class GlassView : public View { 2, ' '}; - OptionsField steps_config{ + AudioVolumeField field_volume{ + {13 * 8, 4 * 16}}; + + /*OptionsField steps_config{ {13 * 8, 4 * 16}, 3, { @@ -238,7 +255,7 @@ class GlassView : public View { {"100", 100}, {"250", 250}, {"500", 500}, - }}; + }};*/ OptionsField scan_type{ {17 * 8, 4 * 16}, diff --git a/firmware/baseband/proc_wideband_spectrum.cpp b/firmware/baseband/proc_wideband_spectrum.cpp index 35aef2ee6..a327caf11 100644 --- a/firmware/baseband/proc_wideband_spectrum.cpp +++ b/firmware/baseband/proc_wideband_spectrum.cpp @@ -60,7 +60,30 @@ void WidebandSpectrum::execute(const buffer_c8_t& buffer) { } } +void WidebandSpectrum::on_signal_message(const RequestSignalMessage& message) { + if (message.signal == RequestSignalMessage::Signal::BeepStopRequest) { + audio::dma::beep_stop(); + } +} + +void WidebandSpectrum::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + void WidebandSpectrum::on_message(const Message* const msg) { + switch (msg->id) { + case Message::ID::RequestSignal: + on_signal_message(*reinterpret_cast(msg)); + return; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(msg)); + return; + + default: + break; + } + const WidebandSpectrumConfigMessage message = *reinterpret_cast(msg); switch (msg->id) { @@ -84,7 +107,6 @@ 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()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_wideband_spectrum.hpp b/firmware/baseband/proc_wideband_spectrum.hpp index ed17a556a..f8858fff8 100644 --- a/firmware/baseband/proc_wideband_spectrum.hpp +++ b/firmware/baseband/proc_wideband_spectrum.hpp @@ -43,6 +43,9 @@ class WidebandSpectrum : public BasebandProcessor { bool configured = false; size_t baseband_fs = 20000000; + void on_beep_message(const AudioBeepMessage& message); + void on_signal_message(const RequestSignalMessage& message); + SpectrumCollector channel_spectrum{}; std::array spectrum{}; From b47cee435e9aaf0fea96dc3c62dde996feecdcd3 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Mon, 25 Mar 2024 00:50:42 +0100 Subject: [PATCH 68/98] fix typo (#2037) --- firmware/application/apps/ui_looking_glass_app.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 0f2f8aa86..ec71c8460 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -54,7 +54,7 @@ void GlassView::update_display_beep() { receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. } else { button_beep_squelch.set_style(&Styles::white); - button_beep_squelch.set_text("[ beep OFF ["); + button_beep_squelch.set_text("[ beep OFF ]"); } } From d9bbd1b9ff54f692079c968dffde9aa15d6618d7 Mon Sep 17 00:00:00 2001 From: ImDroided Date: Mon, 25 Mar 2024 01:21:05 -0500 Subject: [PATCH 69/98] SSTV Freqs (#2038) * Added and fixed freqs Figured I would clean these up and add a bit. * Create SSTV.TXT SSTV Frequencies for SSTV app --- sdcard/FREQMAN/SSTV.TXT | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 sdcard/FREQMAN/SSTV.TXT diff --git a/sdcard/FREQMAN/SSTV.TXT b/sdcard/FREQMAN/SSTV.TXT new file mode 100644 index 000000000..db96dd650 --- /dev/null +++ b/sdcard/FREQMAN/SSTV.TXT @@ -0,0 +1,15 @@ +# Common SSTV frequencies +# frequencies marked Active have more frequent transmissions. +f=3640000,d=SSTV 80M +f=7043000,d=SSTV 40M - Active +f=7170000,d=SSTV 40M - Active +f=10132000,d=SSTV 30M +f=14230000,d=SSTV 20M - Active +f=14233000,d=SSTV 20M - Active +f=14236000,d=SSTV 20M +f=14240000,d=SSTV 20M +f=21340000,d=SSTV 15M - Active +f=28680000,d=SSTV 10M - Active +f=50950000,d=SSTV 6M +f=145625000,d=SSTV 2M +f=433775000,d=SSTV 70CM From d5c8525afc615cdb8b86391e0febbdc0a9a973dc Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Mon, 25 Mar 2024 02:44:49 -0500 Subject: [PATCH 70/98] Declare all folder names in a single source file (#2039) --- firmware/application/CMakeLists.txt | 1 + firmware/application/app_settings.cpp | 5 +- firmware/application/app_settings.hpp | 3 -- firmware/application/apps/acars_app.cpp | 3 +- firmware/application/apps/acars_app.hpp | 2 +- firmware/application/apps/ais_app.cpp | 3 +- firmware/application/apps/ble_comm_app.cpp | 3 +- firmware/application/apps/ble_comm_app.hpp | 2 +- firmware/application/apps/ble_rx_app.cpp | 5 +- firmware/application/apps/ble_rx_app.hpp | 11 ++-- firmware/application/apps/ble_tx_app.cpp | 1 + firmware/application/apps/ble_tx_app.hpp | 7 +-- firmware/application/apps/capture_app.hpp | 3 +- firmware/application/apps/ert_app.cpp | 3 +- firmware/application/apps/pocsag_app.cpp | 3 +- firmware/application/apps/pocsag_app.hpp | 2 +- firmware/application/apps/soundboard_app.cpp | 5 +- firmware/application/apps/tpms_app.cpp | 3 +- firmware/application/apps/ui_adsb_rx.cpp | 3 +- firmware/application/apps/ui_aprs_rx.cpp | 3 +- firmware/application/apps/ui_aprs_rx.hpp | 5 +- .../application/apps/ui_flash_utility.cpp | 11 ++-- firmware/application/apps/ui_freqman.cpp | 1 + firmware/application/apps/ui_fsk_rx.cpp | 3 +- firmware/application/apps/ui_fsk_rx.hpp | 2 +- firmware/application/apps/ui_iq_trim.cpp | 3 +- .../application/apps/ui_looking_glass_app.cpp | 3 +- firmware/application/apps/ui_playlist.cpp | 9 ++-- firmware/application/apps/ui_recon.cpp | 8 +-- firmware/application/apps/ui_recon.hpp | 2 +- .../application/apps/ui_recon_settings.cpp | 1 + firmware/application/apps/ui_remote.cpp | 9 ++-- firmware/application/apps/ui_scanner.cpp | 1 + firmware/application/apps/ui_settings.cpp | 13 ++--- firmware/application/apps/ui_sonde.cpp | 3 +- firmware/application/apps/ui_test.hpp | 2 +- firmware/application/apps/ui_whipcalc.cpp | 3 +- firmware/application/database.cpp | 9 ++-- firmware/application/database.hpp | 8 +-- firmware/application/debug.cpp | 4 +- .../external/afsk_rx/ui_afsk_rx.cpp | 3 +- .../external/afsk_rx/ui_afsk_rx.hpp | 2 +- .../external/spainter/ui_spectrum_painter.cpp | 6 +-- .../external/spainter/ui_spectrum_painter.hpp | 2 +- .../spainter/ui_spectrum_painter_image.cpp | 8 +-- .../spainter/ui_spectrum_painter_image.hpp | 2 +- firmware/application/file_path.cpp | 46 +++++++++++++++++ firmware/application/file_path.hpp | 50 +++++++++++++++++++ firmware/application/freqman_db.cpp | 2 +- firmware/application/freqman_db.hpp | 1 - firmware/application/log_file.hpp | 2 - firmware/application/ui/ui_geomap.cpp | 5 +- firmware/application/ui_navigation.cpp | 7 +-- firmware/application/usb_serial_shell.cpp | 9 ++-- .../common/portapack_persistent_memory.cpp | 9 ++-- .../common/portapack_persistent_memory.hpp | 4 +- 56 files changed, 224 insertions(+), 105 deletions(-) create mode 100644 firmware/application/file_path.cpp create mode 100644 firmware/application/file_path.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 575c50322..8fab990e5 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -190,6 +190,7 @@ set(CPPSRC event_m0.cpp file_reader.cpp file.cpp + file_path.cpp freqman_db.cpp freqman.cpp io_convert.cpp diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index a9e5811b9..ce067e4c2 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -30,6 +30,7 @@ #include "portapack.hpp" #include "portapack_persistent_memory.hpp" #include "utility.hpp" +#include "file_path.hpp" #include #include @@ -40,7 +41,7 @@ using namespace portapack; namespace { fs::path get_settings_path(const std::string& app_name) { - return fs::path{SETTINGS_DIR} / app_name + u".ini"; + return settings_dir / app_name + u".ini"; } } // namespace @@ -156,7 +157,7 @@ bool save_settings(std::string_view store_name, const SettingBindings& bindings) File f; auto path = get_settings_path(std::string{store_name}); - ensure_directory(SETTINGS_DIR); + ensure_directory(settings_dir); auto error = f.create(path); if (error) return false; diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index 0e36ffabf..422daaa36 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -36,9 +36,6 @@ #include "max283x.hpp" #include "string_format.hpp" -// Folder to store app settings, pmem_fileflag, and date_fileflag -#define SETTINGS_DIR u"/SETTINGS" - // Bring in the string_view literal. using std::literals::operator""sv; diff --git a/firmware/application/apps/acars_app.cpp b/firmware/application/apps/acars_app.cpp index c041726c3..a8a5e1f9c 100644 --- a/firmware/application/apps/acars_app.cpp +++ b/firmware/application/apps/acars_app.cpp @@ -24,6 +24,7 @@ #include "baseband_api.hpp" #include "portapack_persistent_memory.hpp" +#include "file_path.hpp" using namespace portapack; using namespace acars; @@ -77,7 +78,7 @@ ACARSAppView::ACARSAppView(NavigationView& nav) logger = std::make_unique(); if (logger) - logger->append(LOG_ROOT_DIR "/ACARS.TXT"); + logger->append(logs_dir / u"ACARS.TXT"); } ACARSAppView::~ACARSAppView() { diff --git a/firmware/application/apps/acars_app.hpp b/firmware/application/apps/acars_app.hpp index 75d11f6bc..fd6886952 100644 --- a/firmware/application/apps/acars_app.hpp +++ b/firmware/application/apps/acars_app.hpp @@ -35,7 +35,7 @@ class ACARSLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp index 5f3fa9a12..0be21bdac 100644 --- a/firmware/application/apps/ais_app.cpp +++ b/firmware/application/apps/ais_app.cpp @@ -23,6 +23,7 @@ #include "string_format.hpp" #include "database.hpp" +#include "file_path.hpp" #include "baseband_api.hpp" @@ -399,7 +400,7 @@ AISAppView::AISAppView(NavigationView& nav) logger = std::make_unique(); if (logger) { - logger->append(LOG_ROOT_DIR "/AIS.TXT"); + logger->append(logs_dir / u"AIS.TXT"); } } diff --git a/firmware/application/apps/ble_comm_app.cpp b/firmware/application/apps/ble_comm_app.cpp index c910f7149..331da938b 100644 --- a/firmware/application/apps/ble_comm_app.cpp +++ b/firmware/application/apps/ble_comm_app.cpp @@ -32,6 +32,7 @@ #include "string_format.hpp" #include "portapack_persistent_memory.hpp" #include "ui_text.hpp" +#include "file_path.hpp" using namespace portapack; using namespace modems; @@ -100,7 +101,7 @@ BLECommView::BLECommView(NavigationView& nav) logging = v; if (logger && logging) - logger->append(LOG_ROOT_DIR "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); + logger->append(logs_dir.string() + "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); }; options_channel.on_change = [this](size_t, int32_t i) { diff --git a/firmware/application/apps/ble_comm_app.hpp b/firmware/application/apps/ble_comm_app.hpp index d94d959b7..a21a03cd7 100644 --- a/firmware/application/apps/ble_comm_app.hpp +++ b/firmware/application/apps/ble_comm_app.hpp @@ -42,7 +42,7 @@ class BLECommLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index 88cdb19ff..1d40ecc15 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -470,10 +470,7 @@ BLERxView::BLERxView(NavigationView& nav) logging = v; if (logger && logging) - logger->append( - "BLERX/Logs" - "/BLELOG_" + - to_string_timestamp(rtc_time::now()) + ".TXT"); + logger->append(blerx_dir.string() + "/Logs/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT"); }; check_log.set_value(logging); diff --git a/firmware/application/apps/ble_rx_app.hpp b/firmware/application/apps/ble_rx_app.hpp index f3e81444d..54560ce02 100644 --- a/firmware/application/apps/ble_rx_app.hpp +++ b/firmware/application/apps/ble_rx_app.hpp @@ -36,12 +36,13 @@ #include "log_file.hpp" #include "utility.hpp" #include "usb_serial_thread.hpp" +#include "file_path.hpp" #include "recent_entries.hpp" class BLELogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } @@ -133,7 +134,7 @@ class BleRecentEntryDetailView : public View { void on_save_file(const std::string value, BLETxPacket packetToSave); bool saveFile(const std::filesystem::path& path, BLETxPacket packetToSave); std::string packetFileBuffer{}; - std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"}; + std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"}; static constexpr uint8_t total_data_lines{5}; @@ -250,9 +251,9 @@ class BLERxView : public View { uint64_t total_count = 0; std::vector searchList{}; - std::filesystem::path find_packet_path{u"BLERX/Find/????.TXT"}; - std::filesystem::path log_packets_path{u"BLERX/Logs/????.TXT"}; - std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"}; + std::filesystem::path find_packet_path{blerx_dir / u"Find/????.TXT"}; + std::filesystem::path log_packets_path{blerx_dir / u"Logs/????.TXT"}; + std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"}; static constexpr auto header_height = 4 * 16; static constexpr auto switch_button_height = 3 * 16; diff --git a/firmware/application/apps/ble_tx_app.cpp b/firmware/application/apps/ble_tx_app.cpp index b226bfddb..013e85402 100644 --- a/firmware/application/apps/ble_tx_app.cpp +++ b/firmware/application/apps/ble_tx_app.cpp @@ -34,6 +34,7 @@ #include "portapack_persistent_memory.hpp" #include "rtc_time.hpp" #include "string_format.hpp" +#include "file_path.hpp" using namespace portapack; using namespace modems; diff --git a/firmware/application/apps/ble_tx_app.hpp b/firmware/application/apps/ble_tx_app.hpp index 438c93222..f28e5aeb3 100644 --- a/firmware/application/apps/ble_tx_app.hpp +++ b/firmware/application/apps/ble_tx_app.hpp @@ -36,6 +36,7 @@ #include "replay_thread.hpp" #include "log_file.hpp" #include "utility.hpp" +#include "file_path.hpp" #include "recent_entries.hpp" @@ -44,7 +45,7 @@ class BLELoggerTx { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } @@ -138,7 +139,7 @@ class BLETxView : public View { uint32_t prev_value{0}; std::filesystem::path file_path{}; - std::filesystem::path packet_save_path{u"BLETX/BLETX_????.TXT"}; + std::filesystem::path packet_save_path{bletx_dir / u"BLETX_????.TXT"}; uint8_t channel_number = 37; bool auto_channel = false; @@ -165,7 +166,7 @@ class BLETxView : public View { std::unique_ptr dataFileWrapper{}; File dataFile{}; - std::filesystem::path dataTempFilePath{u"BLETX/dataFileTemp.TXT"}; + std::filesystem::path dataTempFilePath{bletx_dir / u"dataFileTemp.TXT"}; std::vector markedBytes{}; CursorPos cursor_pos{}; uint8_t marked_counter = 0; diff --git a/firmware/application/apps/capture_app.hpp b/firmware/application/apps/capture_app.hpp index d643bb435..07a162b40 100644 --- a/firmware/application/apps/capture_app.hpp +++ b/firmware/application/apps/capture_app.hpp @@ -31,6 +31,7 @@ #include "ui_spectrum.hpp" #include "app_settings.hpp" #include "radio_state.hpp" +#include "file_path.hpp" namespace ui { @@ -101,7 +102,7 @@ class CaptureAppView : public View { RecordView record_view{ {0 * 8, 2 * 16, 30 * 8, 1 * 16}, u"BBD_????.*", - u"CAPTURES", + captures_dir, RecordView::FileType::RawS16, 16384, 3}; diff --git a/firmware/application/apps/ert_app.cpp b/firmware/application/apps/ert_app.cpp index 107622d84..26b6f7357 100644 --- a/firmware/application/apps/ert_app.cpp +++ b/firmware/application/apps/ert_app.cpp @@ -31,6 +31,7 @@ using namespace portapack; #include "crc.hpp" #include "string_format.hpp" +#include "file_path.hpp" namespace ert { @@ -129,7 +130,7 @@ ERTAppView::ERTAppView(NavigationView& nav) logger = std::make_unique(); if (logger) { - logger->append(LOG_ROOT_DIR "/ERT.TXT"); + logger->append(logs_dir / u"ERT.TXT"); } } diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index 88d4a647b..5d0533e4d 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -27,6 +27,7 @@ #include "portapack_persistent_memory.hpp" #include "string_format.hpp" #include "utility.hpp" +#include "file_path.hpp" using namespace portapack; using namespace pocsag; @@ -115,7 +116,7 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) : FILTER_DROP; } - logger.append(LOG_ROOT_DIR "/POCSAG.TXT"); + logger.append(logs_dir / u"POCSAG.TXT"); field_squelch.set_value(receiver_model.squelch_level()); field_squelch.on_change = [this](int32_t v) { diff --git a/firmware/application/apps/pocsag_app.hpp b/firmware/application/apps/pocsag_app.hpp index ea97ef61a..b03161a6e 100644 --- a/firmware/application/apps/pocsag_app.hpp +++ b/firmware/application/apps/pocsag_app.hpp @@ -39,7 +39,7 @@ class POCSAGLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/apps/soundboard_app.cpp b/firmware/application/apps/soundboard_app.cpp index 304ca2b8a..65cd5e831 100644 --- a/firmware/application/apps/soundboard_app.cpp +++ b/firmware/application/apps/soundboard_app.cpp @@ -28,6 +28,7 @@ #include "tonesets.hpp" #include "ui_tone_key.hpp" #include "audio.hpp" +#include "file_path.hpp" using namespace tonekey; using namespace portapack; @@ -164,7 +165,7 @@ void SoundBoardView::refresh_list() { // List directories and files, put directories up top uint32_t count = 0; - for (const auto& entry : std::filesystem::directory_iterator(u"WAV", u"*")) { + for (const auto& entry : std::filesystem::directory_iterator(wav_dir, u"*")) { if (std::filesystem::is_regular_file(entry.status())) { if (entry.path().string().length()) { auto entry_extension = entry.path().extension().string(); @@ -173,7 +174,7 @@ void SoundBoardView::refresh_list() { c = toupper(c); if (entry_extension == ".WAV") { - if (reader->open(u"/WAV/" + entry.path().native())) { + if (reader->open(wav_dir / entry.path())) { if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) { // sounds[c].ms_duration = reader->ms_duration(); // sounds[c].path = u"WAV/" + entry.path().native(); diff --git a/firmware/application/apps/tpms_app.cpp b/firmware/application/apps/tpms_app.cpp index 54bb7b5df..bf9f14f8e 100644 --- a/firmware/application/apps/tpms_app.cpp +++ b/firmware/application/apps/tpms_app.cpp @@ -30,6 +30,7 @@ using namespace portapack; #include "string_format.hpp" #include "utility.hpp" +#include "file_path.hpp" namespace tpms { @@ -176,7 +177,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { logger = std::make_unique(); if (logger) { - logger->append(LOG_ROOT_DIR "/TPMS.TXT"); + logger->append(logs_dir / u"TPMS.TXT"); } } diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index 9598843d8..9fb60cd84 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -31,6 +31,7 @@ #include "portapack_persistent_memory.hpp" #include "rtc_time.hpp" #include "string_format.hpp" +#include "file_path.hpp" using namespace portapack; @@ -390,7 +391,7 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { }; logger = std::make_unique(); - logger->append(LOG_ROOT_DIR "/ADSB.TXT"); + logger->append(logs_dir / u"ADSB.TXT"); receiver_model.enable(); baseband::set_adsb(); diff --git a/firmware/application/apps/ui_aprs_rx.cpp b/firmware/application/apps/ui_aprs_rx.cpp index a5fa7a6fa..42b75dcf5 100644 --- a/firmware/application/apps/ui_aprs_rx.cpp +++ b/firmware/application/apps/ui_aprs_rx.cpp @@ -27,6 +27,7 @@ #include "baseband_api.hpp" #include "string_format.hpp" #include "portapack_persistent_memory.hpp" +#include "file_path.hpp" using namespace portapack; @@ -111,7 +112,7 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) logger = std::make_unique(); if (logger) - logger->append(LOG_ROOT_DIR "/APRS.TXT"); + logger->append(logs_dir / u"APRS.TXT"); baseband::set_aprs(1200); diff --git a/firmware/application/apps/ui_aprs_rx.hpp b/firmware/application/apps/ui_aprs_rx.hpp index be5c16931..3c3d8337c 100644 --- a/firmware/application/apps/ui_aprs_rx.hpp +++ b/firmware/application/apps/ui_aprs_rx.hpp @@ -36,10 +36,11 @@ #include "log_file.hpp" #include "utility.hpp" +#include "file_path.hpp" class APRSLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } @@ -232,7 +233,7 @@ class APRSRxView : public View { RecordView record_view{ {0 * 8, 1 * 16, 30 * 8, 1 * 16}, u"AFS_????.WAV", - u"APRS", + aprs_dir, RecordView::FileType::WAV, 4096, 4}; diff --git a/firmware/application/apps/ui_flash_utility.cpp b/firmware/application/apps/ui_flash_utility.cpp index 27bccde0e..dafc0f5b2 100644 --- a/firmware/application/apps/ui_flash_utility.cpp +++ b/firmware/application/apps/ui_flash_utility.cpp @@ -23,11 +23,10 @@ #include "ui_flash_utility.hpp" #include "ui_styles.hpp" #include "portapack_shared_memory.hpp" +#include "file_path.hpp" namespace ui { -static const std::filesystem::path firmware_path = u"/FIRMWARE"; - // Firmware image validation static const char* hackrf_magic = "HACKRFFW"; #define FIRMWARE_INFO_AREA_OFFSET 0x400 @@ -84,7 +83,7 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav) menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8}); - ensure_directory(firmware_path); + ensure_directory(firmware_dir); auto add_firmware_items = [&]( const std::filesystem::path& folder_path, @@ -103,8 +102,8 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav) } }; - add_firmware_items(firmware_path, u"*.bin", ui::Color::red()); - add_firmware_items(firmware_path, u"*.tar", ui::Color::purple()); + add_firmware_items(firmware_dir, u"*.bin", ui::Color::red()); + add_firmware_items(firmware_dir, u"*.tar", ui::Color::purple()); // add_firmware_items(user_firmware_folder,u"*.bin", ui::Color::purple()); } @@ -116,7 +115,7 @@ void FlashUtilityView::firmware_selected(std::filesystem::path::string_type path YESNO, [this, path](bool choice) { if (choice) { - std::u16string full_path = std::u16string(u"FIRMWARE/") + path; + std::filesystem::path::string_type full_path = firmware_dir.native() + u"/" + path; this->flash_firmware(full_path); } }); diff --git a/firmware/application/apps/ui_freqman.cpp b/firmware/application/apps/ui_freqman.cpp index 50a44f64b..b3c5db752 100644 --- a/firmware/application/apps/ui_freqman.cpp +++ b/firmware/application/apps/ui_freqman.cpp @@ -31,6 +31,7 @@ #include "ui_receiver.hpp" #include "ui_styles.hpp" #include "utility.hpp" +#include "file_path.hpp" #include diff --git a/firmware/application/apps/ui_fsk_rx.cpp b/firmware/application/apps/ui_fsk_rx.cpp index 6e0c62597..173808589 100644 --- a/firmware/application/apps/ui_fsk_rx.cpp +++ b/firmware/application/apps/ui_fsk_rx.cpp @@ -27,6 +27,7 @@ #include "portapack_persistent_memory.hpp" #include "string_format.hpp" #include "utility.hpp" +#include "file_path.hpp" #include "ui_freqman.hpp" @@ -134,7 +135,7 @@ FskxRxMainView::FskxRxMainView(NavigationView& nav) field_frequency.set_value(initial_target_frequency); deviation_frequency.set_value(initial_deviation); - logger.append(LOG_ROOT_DIR "/FSKRX.TXT"); + logger.append(logs_dir / u"FSKRX.TXT"); baseband::set_fsk(initial_deviation); diff --git a/firmware/application/apps/ui_fsk_rx.hpp b/firmware/application/apps/ui_fsk_rx.hpp index e9e2aca0a..6c9338ca9 100644 --- a/firmware/application/apps/ui_fsk_rx.hpp +++ b/firmware/application/apps/ui_fsk_rx.hpp @@ -42,7 +42,7 @@ class FskRxLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/apps/ui_iq_trim.cpp b/firmware/application/apps/ui_iq_trim.cpp index 88bc2adab..a4e5297ea 100644 --- a/firmware/application/apps/ui_iq_trim.cpp +++ b/firmware/application/apps/ui_iq_trim.cpp @@ -25,6 +25,7 @@ #include "complex.hpp" #include "portapack.hpp" #include "ui_fileman.hpp" +#include "file_path.hpp" using namespace portapack; namespace fs = std::filesystem; @@ -47,7 +48,7 @@ IQTrimView::IQTrimView(NavigationView& nav) field_path.on_select = [this](TextField&) { auto open_view = nav_.push(".C*"); - open_view->push_dir(u"CAPTURES"); + open_view->push_dir(captures_dir); open_view->on_changed = [this](fs::path path) { open_file(path); }; diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index ec71c8460..5679c5a0c 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -26,6 +26,7 @@ #include "file_reader.hpp" #include "string_format.hpp" #include "audio.hpp" +#include "file_path.hpp" using namespace portapack; @@ -571,7 +572,7 @@ void GlassView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // def void GlassView::load_presets() { File presets_file; - auto error = presets_file.open("LOOKINGGLASS/PRESETS.TXT"); + auto error = presets_file.open(looking_glass_dir / u"PRESETS.TXT"); presets_db.clear(); // Add the "Manual" entry. diff --git a/firmware/application/apps/ui_playlist.cpp b/firmware/application/apps/ui_playlist.cpp index 164bb76d0..e08654b80 100644 --- a/firmware/application/apps/ui_playlist.cpp +++ b/firmware/application/apps/ui_playlist.cpp @@ -36,6 +36,7 @@ #include "string_format.hpp" #include "ui_fileman.hpp" #include "utility.hpp" +#include "file_path.hpp" #include #include @@ -130,7 +131,7 @@ void PlaylistView::open_file(bool prompt_save) { } auto open_view = nav_.push(".PPL"); - open_view->push_dir(u"PLAYLIST"); + open_view->push_dir(playlist_dir); open_view->on_changed = [this](fs::path new_file_path) { on_file_changed(new_file_path); }; @@ -169,7 +170,7 @@ void PlaylistView::save_file(bool show_dialogs) { void PlaylistView::add_entry(fs::path&& path) { if (playlist_path_.empty()) { - playlist_path_ = next_filename_matching_pattern(u"/PLAYLIST/PLAY_????.PPL"); + playlist_path_ = next_filename_matching_pattern(playlist_dir / u"PLAY_????.PPL"); // Hack around focus getting called by ctor before parent is set. if (parent()) @@ -387,7 +388,7 @@ PlaylistView::PlaylistView( &waterfall, }); - ensure_directory(u"PLAYLIST"); + ensure_directory(playlist_dir); waterfall.show_audio_spectrum_view(false); field_frequency.set_value(transmitter_model.target_frequency()); @@ -410,7 +411,7 @@ PlaylistView::PlaylistView( if (is_active()) return; auto open_view = nav_.push(".C*"); - open_view->push_dir(u"CAPTURES"); + open_view->push_dir(captures_dir); open_view->on_changed = [this](fs::path path) { add_entry(std::move(path)); }; diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 03f2c8b02..09c0640c2 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -337,7 +337,7 @@ ReconView::ReconView(NavigationView& nav) // set record View record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_AUDIO", u"AUDIO", + u"AUTO_AUDIO", audio_dir, RecordView::FileType::WAV, 4096, 4); record_view->set_filename_date_frequency(true); record_view->set_auto_trim(false); @@ -1170,18 +1170,18 @@ size_t ReconView::change_mode(freqman_index_t new_mod) { if (new_mod == SPEC_MODULATION) { if (persistent_memory::recon_repeat_recorded()) { record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"RECON_REPEAT.C16", u"CAPTURES", + u"RECON_REPEAT.C16", captures_dir, RecordView::FileType::RawS16, 16384, 3); record_view->set_filename_as_is(true); } else { record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_RAW", u"CAPTURES", + u"AUTO_RAW", captures_dir, RecordView::FileType::RawS16, 16384, 3); record_view->set_filename_date_frequency(true); } } else { record_view = std::make_unique(Rect{0, 0, 30 * 8, 1 * 16}, - u"AUTO_AUDIO", u"AUDIO", + u"AUTO_AUDIO", audio_dir, RecordView::FileType::WAV, 4096, 4); record_view->set_filename_date_frequency(true); } diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index d9943f926..e686c2784 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -38,6 +38,7 @@ #include "baseband_api.hpp" #include "string_format.hpp" #include "file.hpp" +#include "file_path.hpp" #include "app_settings.hpp" #include "radio_state.hpp" #include "ui_recon_settings.hpp" @@ -181,7 +182,6 @@ class ReconView : public View { const std::filesystem::path repeat_rec_file = u"RECON_REPEAT.C16"; const std::filesystem::path repeat_rec_meta = u"RECON_REPEAT.TXT"; - const std::filesystem::path repeat_rec_path = u"CAPTURES"; const size_t repeat_read_size{16384}; const size_t repeat_buffer_count{3}; int8_t repeat_cur_rep = 0; diff --git a/firmware/application/apps/ui_recon_settings.cpp b/firmware/application/apps/ui_recon_settings.cpp index 543476af4..b5e7be347 100644 --- a/firmware/application/apps/ui_recon_settings.cpp +++ b/firmware/application/apps/ui_recon_settings.cpp @@ -30,6 +30,7 @@ #include "freqman_db.hpp" #include "portapack.hpp" #include "portapack_persistent_memory.hpp" +#include "file_path.hpp" using namespace std; using namespace portapack; diff --git a/firmware/application/apps/ui_remote.cpp b/firmware/application/apps/ui_remote.cpp index 7b0a13101..f2335ce65 100644 --- a/firmware/application/apps/ui_remote.cpp +++ b/firmware/application/apps/ui_remote.cpp @@ -32,6 +32,7 @@ #include "ui_receiver.hpp" #include "ui_textentry.hpp" #include "utility.hpp" +#include "file_path.hpp" using namespace portapack; namespace fs = std::filesystem; @@ -246,7 +247,7 @@ RemoteEntryEditView::RemoteEntryEditView( field_path.on_select = [this, &nav](TextField&) { auto open_view = nav.push(".C*"); - open_view->push_dir(u"CAPTURES"); + open_view->push_dir(captures_dir); open_view->on_changed = [this](fs::path path) { load_path(std::move(path)); refresh_ui(); @@ -355,7 +356,7 @@ RemoteView::RemoteView( Dim waterfall_height = waterfall_bottom - waterfall_top; waterfall.set_parent_rect({0, waterfall_top, screen_width, waterfall_height}); - ensure_directory(u"REMOTES"); + ensure_directory(remotes_dir); // Load the previously loaded remote if exists. if (!load_remote(settings_.remote_path)) @@ -527,7 +528,7 @@ void RemoteView::new_remote() { void RemoteView::open_remote() { auto open_view = nav_.push(".REM"); - open_view->push_dir(u"REMOTES"); + open_view->push_dir(remotes_dir); open_view->on_changed = [this](fs::path path) { save_remote(); load_remote(std::move(path)); @@ -538,7 +539,7 @@ void RemoteView::open_remote() { void RemoteView::init_remote() { model_ = {"", {}}; reset_buttons(); - set_remote_path(next_filename_matching_pattern(u"/REMOTES/REMOTE_????.REM")); + set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM")); set_needs_save(false); if (remote_path_.empty()) diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index c1e019da7..e6a3c819c 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -26,6 +26,7 @@ #include "optional.hpp" #include "ui_fileman.hpp" #include "ui_freqman.hpp" +#include "file_path.hpp" using namespace portapack; namespace fs = std::filesystem; diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 36bca5adb..9f6c7fc43 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -41,6 +41,7 @@ using namespace lpc43xx; using namespace portapack; #include "file.hpp" +#include "file_path.hpp" namespace fs = std::filesystem; #include "string_format.hpp" @@ -571,17 +572,17 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) { check_use_sdcard_for_pmem.on_select = [this](Checkbox&, bool v) { File pmem_flag_file_handle; if (v) { - if (fs::file_exists(PMEM_FILEFLAG)) { + if (fs::file_exists(settings_dir / PMEM_FILEFLAG)) { text_pmem_status.set("P.Mem flag file present."); } else { - auto error = pmem_flag_file_handle.create(PMEM_FILEFLAG); + auto error = pmem_flag_file_handle.create(settings_dir / PMEM_FILEFLAG); if (error) text_pmem_status.set("Error creating P.Mem File!"); else text_pmem_status.set("P.Mem flag file created."); } } else { - auto result = delete_file(PMEM_FILEFLAG); + auto result = delete_file(settings_dir / PMEM_FILEFLAG); if (result.code() != FR_OK) text_pmem_status.set("Error deleting P.Mem flag!"); else @@ -717,10 +718,10 @@ AppSettingsView::AppSettingsView( menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8}); - ensure_directory(SETTINGS_DIR); + ensure_directory(settings_dir); - for (const auto& entry : std::filesystem::directory_iterator(SETTINGS_DIR, u"*.ini")) { - auto path = (std::filesystem::path)SETTINGS_DIR / entry.path(); + for (const auto& entry : std::filesystem::directory_iterator(settings_dir, u"*.ini")) { + auto path = settings_dir / entry.path(); menu_view.add_item({path.filename().string().substr(0, 26), ui::Color::dark_cyan(), diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 003d80858..281acd0e4 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -25,6 +25,7 @@ #include "baseband_api.hpp" #include "audio.hpp" #include "app_settings.hpp" +#include "file_path.hpp" #include "portapack.hpp" #include @@ -112,7 +113,7 @@ SondeView::SondeView(NavigationView& nav) logger = std::make_unique(); if (logger) - logger->append(LOG_ROOT_DIR "/SONDE.TXT"); + logger->append(logs_dir / u"SONDE.TXT"); audio::output::start(); diff --git a/firmware/application/apps/ui_test.hpp b/firmware/application/apps/ui_test.hpp index 9bf69506f..bb3861bfc 100644 --- a/firmware/application/apps/ui_test.hpp +++ b/firmware/application/apps/ui_test.hpp @@ -38,7 +38,7 @@ class TestLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/apps/ui_whipcalc.cpp b/firmware/application/apps/ui_whipcalc.cpp index 1fdf262bf..8285e66fc 100644 --- a/firmware/application/apps/ui_whipcalc.cpp +++ b/firmware/application/apps/ui_whipcalc.cpp @@ -27,6 +27,7 @@ #include "event_m0.hpp" #include "file_reader.hpp" #include "portapack.hpp" +#include "file_path.hpp" #include @@ -142,7 +143,7 @@ WhipCalcView::WhipCalcView(NavigationView& nav) void WhipCalcView::load_antenna_db() { File antennas_file; - auto error = antennas_file.open("/WHIPCALC/ANTENNAS.TXT"); + auto error = antennas_file.open(whipcalc_dir / u"ANTENNAS.TXT"); if (error) return; diff --git a/firmware/application/database.cpp b/firmware/application/database.cpp index f5d164191..432453b9f 100644 --- a/firmware/application/database.cpp +++ b/firmware/application/database.cpp @@ -23,10 +23,11 @@ #include "database.hpp" #include "file.hpp" +#include "file_path.hpp" #include int database::retrieve_mid_record(MidDBRecord* record, std::string search_term) { - file_path = "AIS/mids.db"; + file_path = ais_dir / u"mids.db"; index_item_length = 4; record_length = 32; @@ -36,7 +37,7 @@ int database::retrieve_mid_record(MidDBRecord* record, std::string search_term) } int database::retrieve_airline_record(AirlinesDBRecord* record, std::string search_term) { - file_path = "ADSB/airlines.db"; + file_path = adsb_dir / u"airlines.db"; index_item_length = 4; record_length = 64; @@ -46,7 +47,7 @@ int database::retrieve_airline_record(AirlinesDBRecord* record, std::string sear } int database::retrieve_aircraft_record(AircraftDBRecord* record, std::string search_term) { - file_path = "ADSB/icao24.db"; + file_path = adsb_dir / u"icao24.db"; index_item_length = 7; record_length = 146; @@ -55,7 +56,7 @@ int database::retrieve_aircraft_record(AircraftDBRecord* record, std::string sea return (result); } -int database::retrieve_record(std::string file_path, int index_item_length, int record_length, void* record, std::string search_term) { +int database::retrieve_record(std::filesystem::path file_path, int index_item_length, int record_length, void* record, std::string search_term) { if (search_term.empty()) return DATABASE_RECORD_NOT_FOUND; diff --git a/firmware/application/database.hpp b/firmware/application/database.hpp index 336c7aa90..4720da87a 100644 --- a/firmware/application/database.hpp +++ b/firmware/application/database.hpp @@ -61,9 +61,9 @@ class database { int retrieve_aircraft_record(AircraftDBRecord* record, std::string search_term); private: - std::string file_path = ""; // path inclusing filename - int index_item_length = 0; // length of index item - int record_length = 0; // length of record + std::filesystem::path file_path = ""; // path including filename + int index_item_length = 0; // length of index item + int record_length = 0; // length of record File db_file{}; int number_of_records = 0; @@ -74,7 +74,7 @@ class database { int result = 0; - int retrieve_record(std::string file_path, int index_item_length, int record_length, void* record, std::string search_term); + int retrieve_record(std::filesystem::path file_path, int index_item_length, int record_length, void* record, std::string search_term); }; #endif /*__DATABASE_H__*/ diff --git a/firmware/application/debug.cpp b/firmware/application/debug.cpp index 745784ce0..4713b6368 100644 --- a/firmware/application/debug.cpp +++ b/firmware/application/debug.cpp @@ -32,6 +32,7 @@ #include "string_format.hpp" #include "ui_styles.hpp" #include "irq_controls.hpp" +#include "file_path.hpp" using namespace ui; @@ -266,7 +267,6 @@ bool stack_dump() { bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag) { Painter painter; - std::string debug_dir = "DEBUG"; std::filesystem::path filename{}; File dump_file{}; bool error; @@ -277,7 +277,7 @@ bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag) { bool data_found{false}; ensure_directory(debug_dir); - filename = next_filename_matching_pattern(debug_dir + "/" + (stack_flag ? "STACK" : "MEMORY") + "_DUMP_????.TXT"); + filename = next_filename_matching_pattern(debug_dir + (stack_flag ? u"/STACK" : u"/MEMORY") + u"_DUMP_????.TXT"); error = filename.empty(); if (!error) error = dump_file.create(filename) != 0; diff --git a/firmware/application/external/afsk_rx/ui_afsk_rx.cpp b/firmware/application/external/afsk_rx/ui_afsk_rx.cpp index 2b43ca233..626ff76e5 100644 --- a/firmware/application/external/afsk_rx/ui_afsk_rx.cpp +++ b/firmware/application/external/afsk_rx/ui_afsk_rx.cpp @@ -29,6 +29,7 @@ #include "baseband_api.hpp" #include "string_format.hpp" #include "portapack_persistent_memory.hpp" +#include "file_path.hpp" using namespace portapack; using namespace modems; @@ -84,7 +85,7 @@ AFSKRxView::AFSKRxView(NavigationView& nav) logger = std::make_unique(); if (logger) - logger->append(LOG_ROOT_DIR "/AFSK.TXT"); + logger->append(logs_dir / u"AFSK.TXT"); // Auto-configure modem for LCR RX (will be removed later) baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false); diff --git a/firmware/application/external/afsk_rx/ui_afsk_rx.hpp b/firmware/application/external/afsk_rx/ui_afsk_rx.hpp index 188cd5df8..2e0794cff 100644 --- a/firmware/application/external/afsk_rx/ui_afsk_rx.hpp +++ b/firmware/application/external/afsk_rx/ui_afsk_rx.hpp @@ -40,7 +40,7 @@ namespace ui::external_app::afsk_rx { class AFSKLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/external/spainter/ui_spectrum_painter.cpp b/firmware/application/external/spainter/ui_spectrum_painter.cpp index 8b680b5fd..ceeb1f816 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter.cpp +++ b/firmware/application/external/spainter/ui_spectrum_painter.cpp @@ -76,15 +76,15 @@ SpectrumPainterView::SpectrumPainterView( transmitter_model.set_rf_amp(rf_amp); }; - input_image.on_input_avaliable = [this]() { - image_input_avaliable = true; + input_image.on_input_available = [this]() { + image_input_available = true; }; button_play.on_select = [this](ImageButton&) { if (tx_active == false) { tx_mode = tab_view.selected(); - if (tx_mode == 0 && image_input_avaliable == false) + if (tx_mode == 0 && image_input_available == false) return; /* By experimental test measurement, we got a good painted spectrum quality when selecting a BW GUI App range from 100k ... 2M aprox. In that range , the best TX LPF filter = 1M75 (the min) diff --git a/firmware/application/external/spainter/ui_spectrum_painter.hpp b/firmware/application/external/spainter/ui_spectrum_painter.hpp index 40f3939c1..ba780a672 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter.hpp +++ b/firmware/application/external/spainter/ui_spectrum_painter.hpp @@ -61,7 +61,7 @@ class SpectrumPainterView : public View { app_settings::SettingsManager settings_{ "tx_painter", app_settings::Mode::TX}; - bool image_input_avaliable{false}; + bool image_input_available{false}; bool tx_active{false}; uint32_t tx_mode{0}; uint16_t tx_current_line{0}; diff --git a/firmware/application/external/spainter/ui_spectrum_painter_image.cpp b/firmware/application/external/spainter/ui_spectrum_painter_image.cpp index 5f26ec86a..fd2e8cb18 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter_image.cpp +++ b/firmware/application/external/spainter/ui_spectrum_painter_image.cpp @@ -28,6 +28,7 @@ #include "io_file.hpp" #include "file.hpp" #include "portapack_persistent_memory.hpp" +#include "file_path.hpp" namespace ui::external_app::spainter { @@ -39,15 +40,14 @@ SpectrumInputImageView::SpectrumInputImageView(NavigationView& nav) { button_load_image.on_select = [this, &nav](Button&) { auto open_view = nav.push(".bmp"); - constexpr auto data_directory = u"SPECTRUM"; - ensure_directory(data_directory); - open_view->push_dir(data_directory); + ensure_directory(spectrum_dir); + open_view->push_dir(spectrum_dir); open_view->on_changed = [this](std::filesystem::path new_file_path) { this->file = new_file_path.string(); painted = false; this->set_dirty(); - this->on_input_avaliable(); + this->on_input_available(); }; }; } diff --git a/firmware/application/external/spainter/ui_spectrum_painter_image.hpp b/firmware/application/external/spainter/ui_spectrum_painter_image.hpp index d4ae6cd92..711e8f27a 100644 --- a/firmware/application/external/spainter/ui_spectrum_painter_image.hpp +++ b/firmware/application/external/spainter/ui_spectrum_painter_image.hpp @@ -46,7 +46,7 @@ class SpectrumInputImageView : public View { uint16_t get_height(); std::vector get_line(uint16_t); - std::function on_input_avaliable{}; + std::function on_input_available{}; private: bool painted{false}; diff --git a/firmware/application/file_path.cpp b/firmware/application/file_path.cpp new file mode 100644 index 000000000..9188d2a5a --- /dev/null +++ b/firmware/application/file_path.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "file_path.hpp" +#include "file.hpp" + +const std::filesystem::path adsb_dir = u"ADSB"; +const std::filesystem::path ais_dir = u"AIS"; +const std::filesystem::path aprs_dir = u"APRS"; +const std::filesystem::path audio_dir = u"AUDIO"; +const std::filesystem::path blerx_dir = u"BLERX"; +const std::filesystem::path bletx_dir = u"BLETX"; +const std::filesystem::path captures_dir = u"CAPTURES"; +const std::filesystem::path debug_dir = u"DEBUG"; +const std::filesystem::path firmware_dir = u"FIRMWARE"; +const std::filesystem::path freqman_dir = u"FREQMAN"; +const std::filesystem::path logs_dir = u"LOGS"; +const std::filesystem::path looking_glass_dir = u"LOOKINGGLASS"; +const std::filesystem::path playlist_dir = u"PLAYLIST"; +const std::filesystem::path remotes_dir = u"REMOTES"; +const std::filesystem::path repeat_rec_path = u"CAPTURES"; +const std::filesystem::path screenshots_dir = u"SCREENSHOTS"; +const std::filesystem::path settings_dir = u"SETTINGS"; +const std::filesystem::path spectrum_dir = u"SPECTRUM"; +const std::filesystem::path splash_dir = u"SPLASH"; +const std::filesystem::path sstv_dir = u"SSTV"; +const std::filesystem::path wav_dir = u"WAV"; +const std::filesystem::path whipcalc_dir = u"WHIPCALC"; diff --git a/firmware/application/file_path.hpp b/firmware/application/file_path.hpp new file mode 100644 index 000000000..7661ab22a --- /dev/null +++ b/firmware/application/file_path.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 Mark Thompson + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FILE_PATH_H__ +#define __FILE_PATH_H__ + +#include "file.hpp" + +extern const std::filesystem::path adsb_dir; +extern const std::filesystem::path ais_dir; +extern const std::filesystem::path aprs_dir; +extern const std::filesystem::path audio_dir; +extern const std::filesystem::path blerx_dir; +extern const std::filesystem::path bletx_dir; +extern const std::filesystem::path captures_dir; +extern const std::filesystem::path debug_dir; +extern const std::filesystem::path firmware_dir; +extern const std::filesystem::path freqman_dir; +extern const std::filesystem::path logs_dir; +extern const std::filesystem::path looking_glass_dir; +extern const std::filesystem::path playlist_dir; +extern const std::filesystem::path remotes_dir; +extern const std::filesystem::path repeat_rec_path; +extern const std::filesystem::path screenshots_dir; +extern const std::filesystem::path settings_dir; +extern const std::filesystem::path spectrum_dir; +extern const std::filesystem::path splash_dir; +extern const std::filesystem::path sstv_dir; +extern const std::filesystem::path wav_dir; +extern const std::filesystem::path whipcalc_dir; + +#endif /* __FILE_PATH_H__ */ diff --git a/firmware/application/freqman_db.cpp b/firmware/application/freqman_db.cpp index e676d3b9b..61a071e5e 100644 --- a/firmware/application/freqman_db.cpp +++ b/firmware/application/freqman_db.cpp @@ -29,6 +29,7 @@ #include "string_format.hpp" #include "tone_key.hpp" #include "utility.hpp" +#include "file_path.hpp" #include #include @@ -37,7 +38,6 @@ namespace fs = std::filesystem; -const std::filesystem::path freqman_dir{u"/FREQMAN"}; const std::filesystem::path freqman_extension{u".TXT"}; // NB: Don't include UI headers to keep this code unit testable. diff --git a/firmware/application/freqman_db.hpp b/firmware/application/freqman_db.hpp index 6e1a1d7b7..2fed7a930 100644 --- a/firmware/application/freqman_db.hpp +++ b/firmware/application/freqman_db.hpp @@ -36,7 +36,6 @@ #include /* Defined in freqman_db.cpp */ -extern const std::filesystem::path freqman_dir; extern const std::filesystem::path freqman_extension; using freqman_index_t = uint8_t; diff --git a/firmware/application/log_file.hpp b/firmware/application/log_file.hpp index 9ec0e3fe5..430bf14ae 100644 --- a/firmware/application/log_file.hpp +++ b/firmware/application/log_file.hpp @@ -27,8 +27,6 @@ #include "file.hpp" #include "rtc_time.hpp" -#define LOG_ROOT_DIR "LOGS" - class LogFile { public: Optional append(const std::filesystem::path& filename) { diff --git a/firmware/application/ui/ui_geomap.cpp b/firmware/application/ui/ui_geomap.cpp index 75829854d..3b48a95a6 100644 --- a/firmware/application/ui/ui_geomap.cpp +++ b/firmware/application/ui/ui_geomap.cpp @@ -34,6 +34,7 @@ using namespace portapack; #include "complex.hpp" #include "ui_styles.hpp" #include "ui_font_fixed_5x8.hpp" +#include "file_path.hpp" namespace ui { @@ -447,7 +448,7 @@ void GeoMap::move(const float lon, const float lat) { } bool GeoMap::init() { - auto result = map_file.open("ADSB/world_map.bin"); + auto result = map_file.open(adsb_dir / u"world_map.bin"); map_opened = !result.is_valid(); if (map_opened) { @@ -613,7 +614,7 @@ void GeoMapView::focus() { geopos.focus(); if (!geomap.map_file_opened()) - nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT); + nav_.display_modal("No map", "No world_map.bin file in\n/" + adsb_dir.string() + "/ directory", ABORT); } void GeoMapView::update_my_position(float lat, float lon, int32_t altitude) { diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index d417002d7..a8a6f2bcc 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -106,6 +106,7 @@ #include "file.hpp" #include "file_reader.hpp" #include "png_writer.hpp" +#include "file_path.hpp" using portapack::receiver_model; using portapack::transmitter_model; @@ -473,8 +474,8 @@ void SystemStatusView::on_bias_tee() { } void SystemStatusView::on_camera() { - ensure_directory("SCREENSHOTS"); - auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG"); + ensure_directory(screenshots_dir); + auto path = next_filename_matching_pattern(screenshots_dir / u"SCR_????.PNG"); if (path.empty()) return; @@ -535,7 +536,7 @@ void SystemStatusView::rtc_battery_workaround() { } } } else { - ensure_directory(SETTINGS_DIR); + ensure_directory(settings_dir); make_new_file(DATE_FILEFLAG); year = 1980; diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 21fc12c01..6aba0f14d 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -44,6 +44,7 @@ #include "ui_flash_utility.hpp" #include "untar.hpp" #include "ui_widget.hpp" +#include "file_path.hpp" #include "ui_navigation.hpp" #include "usb_serial_shell_filesystem.hpp" @@ -167,8 +168,8 @@ static void cmd_screenshot(BaseSequentialStream* chp, int argc, char* argv[]) { (void)argc; (void)argv; - ensure_directory("SCREENSHOTS"); - auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG"); + ensure_directory(screenshots_dir); + auto path = next_filename_matching_pattern(screenshots_dir / u"SCR_????.PNG"); if (path.empty()) return; @@ -1037,9 +1038,9 @@ static void cmd_settingsreset(BaseSequentialStream* chp, int argc, char* argv[]) if (!nav) return; nav->home(true); // to exit all running apps - for (const auto& entry : std::filesystem::directory_iterator(SETTINGS_DIR, u"*.ini")) { + for (const auto& entry : std::filesystem::directory_iterator(settings_dir, u"*.ini")) { if (std::filesystem::is_regular_file(entry.status())) { - std::filesystem::path pth = SETTINGS_DIR; + std::filesystem::path pth = settings_dir; pth += u"/" + entry.path(); chprintf(chp, pth.string().c_str()); chprintf(chp, "\r\n"); diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index b904722be..4fe7aa62a 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -37,6 +37,7 @@ #include "ui_flash_utility.hpp" #include "utility.hpp" #include "rtc_time.hpp" +#include "file_path.hpp" #include #include @@ -1105,14 +1106,14 @@ void set_menu_color(Color v) { // PMem to sdcard settings bool should_use_sdcard_for_pmem() { - return std::filesystem::file_exists(PMEM_FILEFLAG); + return std::filesystem::file_exists(settings_dir / PMEM_FILEFLAG); } int save_persistent_settings_to_file() { File outfile; - ensure_directory(SETTINGS_DIR); - auto error = outfile.create(PMEM_SETTING_FILE); + ensure_directory(settings_dir); + auto error = outfile.create(settings_dir / PMEM_SETTING_FILE); if (error) return false; @@ -1122,7 +1123,7 @@ int save_persistent_settings_to_file() { int load_persistent_settings_from_file() { File infile; - auto error = infile.open(PMEM_SETTING_FILE); + auto error = infile.open(settings_dir / PMEM_SETTING_FILE); if (error) return false; diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 6c40fa3a6..397c79aba 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -37,10 +37,10 @@ #include "ui.hpp" // persistent memory from/to sdcard flag file -#define PMEM_FILEFLAG u"/SETTINGS/PMEM_FILEFLAG" +#define PMEM_FILEFLAG u"PMEM_FILEFLAG" // persistent memory from/to sdcard flag file -#define PMEM_SETTING_FILE u"/SETTINGS/pmem_settings" +#define PMEM_SETTING_FILE u"pmem_settings" #define PMEM_SIZE_BYTES 256 // total amount of pmem space in bytes, including checksum #define PMEM_SIZE_WORDS (PMEM_SIZE_BYTES / 4) From 264fa9a28eb11c35a2ba6aa961bb4450a6dc4234 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Tue, 26 Mar 2024 11:32:24 -0500 Subject: [PATCH 71/98] Continued folder names consolidation & GPS default folder (#2042) * Continued folder names consolidation * Clang --- firmware/application/apps/ble_rx_app.cpp | 2 +- firmware/application/apps/ble_tx_app.cpp | 2 +- firmware/application/apps/replay_app.cpp | 2 +- firmware/application/apps/ui_recon.cpp | 2 +- .../application/external/gpssim/gps_sim_app.cpp | 5 ++++- firmware/application/file_path.cpp | 3 +++ firmware/application/file_path.hpp | 3 +++ .../application/ui_external_items_menu_loader.cpp | 13 +++++++------ firmware/application/ui_navigation.cpp | 4 +++- firmware/application/usb_serial_shell.cpp | 2 +- 10 files changed, 25 insertions(+), 13 deletions(-) diff --git a/firmware/application/apps/ble_rx_app.cpp b/firmware/application/apps/ble_rx_app.cpp index 1d40ecc15..be03b53b1 100644 --- a/firmware/application/apps/ble_rx_app.cpp +++ b/firmware/application/apps/ble_rx_app.cpp @@ -765,7 +765,7 @@ void BLERxView::on_filter_change(std::string value) { } void BLERxView::on_file_changed(const std::filesystem::path& new_file_path) { - file_path = fs::path(u"/") + new_file_path; + file_path = new_file_path; found_count = 0; total_count = 0; searchList.clear(); diff --git a/firmware/application/apps/ble_tx_app.cpp b/firmware/application/apps/ble_tx_app.cpp index 013e85402..d9680c4d4 100644 --- a/firmware/application/apps/ble_tx_app.cpp +++ b/firmware/application/apps/ble_tx_app.cpp @@ -449,7 +449,7 @@ BLETxView::BLETxView( } void BLETxView::on_file_changed(const fs::path& new_file_path) { - file_path = fs::path(u"/") + new_file_path; + file_path = new_file_path; num_packets = 0; { // Get the size of the data file. diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp index bc7d8b9ff..832b41c6c 100644 --- a/firmware/application/apps/replay_app.cpp +++ b/firmware/application/apps/replay_app.cpp @@ -44,7 +44,7 @@ void ReplayAppView::set_ready() { } void ReplayAppView::on_file_changed(const fs::path& new_file_path) { - file_path = fs::path(u"/") + new_file_path; + file_path = new_file_path; File::Size file_size{}; { // Get the size of the data file. diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 09c0640c2..afa3782f0 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -1460,7 +1460,7 @@ void ReconView::handle_repeat_thread_done(const uint32_t return_code) { stop_repeat(true); } else if (return_code == ReplayThread::READ_ERROR) { stop_repeat(false); - repeat_file_error(u"/" + repeat_rec_path + u"/" + repeat_rec_file, "Can't open file to send."); + repeat_file_error(rawfile, "Can't open file to send."); } } diff --git a/firmware/application/external/gpssim/gps_sim_app.cpp b/firmware/application/external/gpssim/gps_sim_app.cpp index ff5e73f25..2ee41de6a 100644 --- a/firmware/application/external/gpssim/gps_sim_app.cpp +++ b/firmware/application/external/gpssim/gps_sim_app.cpp @@ -28,6 +28,7 @@ #include "io_file.hpp" #include "metadata_file.hpp" #include "utility.hpp" +#include "file_path.hpp" #include "baseband_api.hpp" #include "portapack.hpp" @@ -43,7 +44,7 @@ void GpsSimAppView::set_ready() { } void GpsSimAppView::on_file_changed(const fs::path& new_file_path) { - file_path = fs::path(u"/") + new_file_path; + file_path = new_file_path; File::Size file_size{}; { // Get the size of the data file. @@ -185,6 +186,8 @@ GpsSimAppView::GpsSimAppView( button_open.on_select = [this, &nav](Button&) { auto open_view = nav.push(".C8"); + ensure_directory(gps_dir); + open_view->push_dir(gps_dir); open_view->on_changed = [this](std::filesystem::path new_file_path) { on_file_changed(new_file_path); }; diff --git a/firmware/application/file_path.cpp b/firmware/application/file_path.cpp index 9188d2a5a..a56e141f3 100644 --- a/firmware/application/file_path.cpp +++ b/firmware/application/file_path.cpp @@ -24,6 +24,7 @@ const std::filesystem::path adsb_dir = u"ADSB"; const std::filesystem::path ais_dir = u"AIS"; +const std::filesystem::path apps_dir = u"APPS"; const std::filesystem::path aprs_dir = u"APRS"; const std::filesystem::path audio_dir = u"AUDIO"; const std::filesystem::path blerx_dir = u"BLERX"; @@ -32,11 +33,13 @@ const std::filesystem::path captures_dir = u"CAPTURES"; const std::filesystem::path debug_dir = u"DEBUG"; const std::filesystem::path firmware_dir = u"FIRMWARE"; const std::filesystem::path freqman_dir = u"FREQMAN"; +const std::filesystem::path gps_dir = u"GPS"; const std::filesystem::path logs_dir = u"LOGS"; const std::filesystem::path looking_glass_dir = u"LOOKINGGLASS"; const std::filesystem::path playlist_dir = u"PLAYLIST"; const std::filesystem::path remotes_dir = u"REMOTES"; const std::filesystem::path repeat_rec_path = u"CAPTURES"; +const std::filesystem::path samples_dir = u"SAMPLES"; const std::filesystem::path screenshots_dir = u"SCREENSHOTS"; const std::filesystem::path settings_dir = u"SETTINGS"; const std::filesystem::path spectrum_dir = u"SPECTRUM"; diff --git a/firmware/application/file_path.hpp b/firmware/application/file_path.hpp index 7661ab22a..802ee8686 100644 --- a/firmware/application/file_path.hpp +++ b/firmware/application/file_path.hpp @@ -26,6 +26,7 @@ extern const std::filesystem::path adsb_dir; extern const std::filesystem::path ais_dir; +extern const std::filesystem::path apps_dir; extern const std::filesystem::path aprs_dir; extern const std::filesystem::path audio_dir; extern const std::filesystem::path blerx_dir; @@ -34,11 +35,13 @@ extern const std::filesystem::path captures_dir; extern const std::filesystem::path debug_dir; extern const std::filesystem::path firmware_dir; extern const std::filesystem::path freqman_dir; +extern const std::filesystem::path gps_dir; extern const std::filesystem::path logs_dir; extern const std::filesystem::path looking_glass_dir; extern const std::filesystem::path playlist_dir; extern const std::filesystem::path remotes_dir; extern const std::filesystem::path repeat_rec_path; +extern const std::filesystem::path samples_dir; extern const std::filesystem::path screenshots_dir; extern const std::filesystem::path settings_dir; extern const std::filesystem::path spectrum_dir; diff --git a/firmware/application/ui_external_items_menu_loader.cpp b/firmware/application/ui_external_items_menu_loader.cpp index 98fbe60e8..48cb7ab70 100644 --- a/firmware/application/ui_external_items_menu_loader.cpp +++ b/firmware/application/ui_external_items_menu_loader.cpp @@ -1,6 +1,7 @@ #include "ui_external_items_menu_loader.hpp" #include "sd_card.hpp" +#include "file_path.hpp" namespace ui { @@ -11,8 +12,8 @@ namespace ui { if (!callback) return; if (sd_card::status() != sd_card::Status::Mounted) return; - for (const auto& entry : std::filesystem::directory_iterator(u"APPS", u"*.ppma")) { - auto filePath = u"/APPS/" + entry.path(); + for (const auto& entry : std::filesystem::directory_iterator(apps_dir, u"*.ppma")) { + auto filePath = apps_dir / entry.path(); File app; auto openError = app.open(filePath); @@ -52,8 +53,8 @@ namespace ui { if (sd_card::status() != sd_card::Status::Mounted) return external_apps; - for (const auto& entry : std::filesystem::directory_iterator(u"APPS", u"*.ppma")) { - auto filePath = u"/APPS/" + entry.path(); + for (const auto& entry : std::filesystem::directory_iterator(apps_dir, u"*.ppma")) { + auto filePath = apps_dir / entry.path(); File app; auto openError = app.open(filePath); @@ -86,7 +87,7 @@ namespace ui { gridItem.on_select = [&nav, app_location, filePath]() { if (!run_external_app(nav, filePath)) { - nav.display_modal("Error", "The .ppma file in your APPS\nfolder can't be read. Please\nupdate your SD Card content."); + nav.display_modal("Error", "The .ppma file in your " + apps_dir.string() + "\nfolder can't be read. Please\nupdate your SD Card content."); } }; } else { @@ -95,7 +96,7 @@ namespace ui { gridItem.bitmap = &bitmap_sd_card_error; gridItem.on_select = [&nav]() { - nav.display_modal("Error", "The .ppma file in your APPS\nfolder is outdated. Please\nupdate your SD Card content."); + nav.display_modal("Error", "The .ppma file in your " + apps_dir.string() + "\nfolder is outdated. Please\nupdate your SD Card content."); }; } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a8a6f2bcc..a48924385 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -719,6 +719,7 @@ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc) }; } +// clang-format off void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView& grid) { auto externalItems = ExternalItemsMenuLoader::load_external_items(location, nav); if (externalItems.empty()) { @@ -730,7 +731,7 @@ void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView& "Notice", "External app directory empty;\n" "see Mayhem wiki and copy apps\n" - "to APPS folder of SD card."); + "to " + apps_dir.string() + " folder of SD card."); }}); } else { for (auto const& gridItem : externalItems) { @@ -738,6 +739,7 @@ void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView& } } } +// clang-format on /* ReceiversMenuView *****************************************************/ diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 6aba0f14d..768f4ff7f 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -665,7 +665,7 @@ static void cmd_appstart(BaseSequentialStream* chp, int argc, char* argv[]) { return; } // since ext app loader changed, we can just pass the string to it, and it"ll return if started or not. - std::string appwithpath = "/APPS/"; + std::string appwithpath = "/" + apps_dir.string() + "/"; appwithpath += argv[0]; appwithpath += ".ppma"; bool ret = ui::ExternalItemsMenuLoader::run_external_app(*nav, path_from_string8((char*)appwithpath.c_str())); From fa56cdd015183109572bea37aff33905c8917ce7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 28 Mar 2024 10:57:40 +1000 Subject: [PATCH 72/98] Adding Australian UHF channels and Brisbane Airband to FREQMAN, adding Australian UHF to Looking Glass (#2048) --- sdcard/FREQMAN/AUS_BNE_AIRBAND.TXT | 11 ++++ sdcard/FREQMAN/CB_UHF_AUSTRALIA.txt | 80 +++++++++++++++++++++++++++++ sdcard/LOOKINGGLASS/PRESETS.TXT | 2 + 3 files changed, 93 insertions(+) create mode 100644 sdcard/FREQMAN/AUS_BNE_AIRBAND.TXT create mode 100644 sdcard/FREQMAN/CB_UHF_AUSTRALIA.txt diff --git a/sdcard/FREQMAN/AUS_BNE_AIRBAND.TXT b/sdcard/FREQMAN/AUS_BNE_AIRBAND.TXT new file mode 100644 index 000000000..9e34f3b59 --- /dev/null +++ b/sdcard/FREQMAN/AUS_BNE_AIRBAND.TXT @@ -0,0 +1,11 @@ +f=124700000,m=AM,bw=DSB 6k,d=BNE Approach NW +f=123500000,m=AM,bw=DSB 6k,d=BNE Approach 2 +f=125600000,m=AM,bw=DSB 6k,d=BNE Approach 3 +f=120500000,m=AM,bw=DSB 6k,d=BNE RWY 19L/01R +f=118000000,m=AM,bw=DSB 6k,d=BNE RWY 19R/01L +f=113200000,m=AM,bw=DSB 6k,d=BNE ATIS 1 +f=125500000,m=AM,bw=DSB 6k,d=BNE ATIS 2 +f=121700000,m=AM,bw=DSB 6k,d=BNE GRND 1 +f=122250000,m=AM,bw=DSB 6k,d=BNE GRND 2 +f=124050000,m=AM,bw=DSB 6k,d=BNE GRND 3 +f=125700000,m=AM,bw=DSB 6k,d=OOL Approach E \ No newline at end of file diff --git a/sdcard/FREQMAN/CB_UHF_AUSTRALIA.txt b/sdcard/FREQMAN/CB_UHF_AUSTRALIA.txt new file mode 100644 index 000000000..ddcfb465e --- /dev/null +++ b/sdcard/FREQMAN/CB_UHF_AUSTRALIA.txt @@ -0,0 +1,80 @@ +f=476425000,m=NFM,bw=8k5,d=CH 1 Repeater +f=476450000,m=NFM,bw=8k5,d=CH 2 Repeater +f=476475000,m=NFM,bw=8k5,d=CH 3 Repeater +f=476500000,m=NFM,bw=8k5,d=CH 4 Repeater +f=476525000,m=NFM,bw=8k5,d=CH 5 Emergency Repeater +f=476550000,m=NFM,bw=8k5,d=CH 6 Repeater +f=476575000,m=NFM,bw=8k5,d=CH 7 Repeater +f=476600000,m=NFM,bw=8k5,d=CH 8 Repeater +f=476625000,m=NFM,bw=8k5,d=CH 9 Gen Chat +f=476650000,m=NFM,bw=8k5,d=CH 10 Recreational +f=476675000,m=NFM,bw=8k5,d=CH 11 Call Channel +f=476700000,m=NFM,bw=8k5,d=CH 12 Gen Chat +f=476725000,m=NFM,bw=8k5,d=CH 13 Gen Chat +f=476750000,m=NFM,bw=8k5,d=CH 14 Gen Chat +f=476775000,m=NFM,bw=8k5,d=CH 15 Gen Chat +f=476800000,m=NFM,bw=8k5,d=CH 16 Gen Chat +f=476825000,m=NFM,bw=8k5,d=CH 17 Gen Chat +f=476850000,m=NFM,bw=8k5,d=CH 18 Convoys +f=476875000,m=NFM,bw=8k5,d=CH 19 Gen Chat +f=476900000,m=NFM,bw=8k5,d=CH 20 Gen Chat +f=476925000,m=NFM,bw=8k5,d=CH 21 Gen Chat +f=476950000,m=NFM,bw=8k5,d=CH 22 Telemetry +f=476975000,m=NFM,bw=8k5,d=CH 23 Telemetry +f=477000000,m=NFM,bw=8k5,d=CH 24 Gen Chat +f=477025000,m=NFM,bw=8k5,d=CH 25 Gen Chat +f=477050000,m=NFM,bw=8k5,d=CH 26 Gen Chat +f=477075000,m=NFM,bw=8k5,d=CH 27 Gen Chat +f=477100000,m=NFM,bw=8k5,d=CH 28 Gen Chat +f=477125000,m=NFM,bw=8k5,d=CH 29 Road Safety +f=477150000,m=NFM,bw=8k5,d=CH 30 Broadcasts +f=477175000,m=NFM,bw=8k5,d=CH 31 Repeater +f=477200000,m=NFM,bw=8k5,d=CH 32 Repeater +f=477225000,m=NFM,bw=8k5,d=CH 33 Repeater +f=477250000,m=NFM,bw=8k5,d=CH 34 Repeater +f=477275000,m=NFM,bw=8k5,d=CH 35 Emergency Repeater +f=477300000,m=NFM,bw=8k5,d=CH 36 Repeater +f=477325000,m=NFM,bw=8k5,d=CH 37 Repeater +f=477350000,m=NFM,bw=8k5,d=CH 38 Repeater +f=477375000,m=NFM,bw=8k5,d=CH 39 Gen Chat +f=477400000,m=NFM,bw=8k5,d=CH 40 Road Safety +f=476437500,m=NFM,bw=8k5,d=CH 41 Repeater +f=476462500,m=NFM,bw=8k5,d=CH 42 Repeater +f=476487500,m=NFM,bw=8k5,d=CH 43 Repeater +f=476512500,m=NFM,bw=8k5,d=CH 44 Repeater +f=476537500,m=NFM,bw=8k5,d=CH 45 Repeater +f=476562500,m=NFM,bw=8k5,d=CH 46 Repeater +f=476587500,m=NFM,bw=8k5,d=CH 47 Repeater +f=476612500,m=NFM,bw=8k5,d=CH 48 Repeater +f=476637500,m=NFM,bw=8k5,d=CH 49 Gen Chat +f=476662500,m=NFM,bw=8k5,d=CH 50 Gen Chat +f=476687500,m=NFM,bw=8k5,d=CH 51 Gen Chat +f=476712500,m=NFM,bw=8k5,d=CH 52 Gen Chat +f=476737500,m=NFM,bw=8k5,d=CH 53 Gen Chat +f=476762500,m=NFM,bw=8k5,d=CH 54 Gen Chat +f=476787500,m=NFM,bw=8k5,d=CH 55 Gen Chat +f=476812500,m=NFM,bw=8k5,d=CH 56 Gen Chat +f=476837500,m=NFM,bw=8k5,d=CH 57 Gen Chat +f=476862500,m=NFM,bw=8k5,d=CH 58 Gen Chat +f=476887500,m=NFM,bw=8k5,d=CH 59 Gen Chat +f=476912500,m=NFM,bw=8k5,d=CH 60 Gen Chat +f=476937500,m=NFM,bw=8k5,d=CH 61 Reserved +f=476962500,m=NFM,bw=8k5,d=CH 62 Reserved +f=476987500,m=NFM,bw=8k5,d=CH 63 Reserved +f=477012500,m=NFM,bw=8k5,d=CH 64 Gen Chat +f=477037500,m=NFM,bw=8k5,d=CH 65 Gen Chat +f=477062500,m=NFM,bw=8k5,d=CH 66 Gen Chat +f=477087500,m=NFM,bw=8k5,d=CH 67 Gen Chat +f=477112500,m=NFM,bw=8k5,d=CH 68 Gen Chat +f=477137500,m=NFM,bw=8k5,d=CH 69 Gen Chat +f=477162500,m=NFM,bw=8k5,d=CH 70 Gen Chat +f=477187500,m=NFM,bw=8k5,d=CH 71 Repeater +f=477212500,m=NFM,bw=8k5,d=CH 72 Repeater +f=477237500,m=NFM,bw=8k5,d=CH 73 Repeater +f=477262500,m=NFM,bw=8k5,d=CH 74 Repeater +f=477287500,m=NFM,bw=8k5,d=CH 75 Repeater +f=477312500,m=NFM,bw=8k5,d=CH 76 Repeater +f=477337500,m=NFM,bw=8k5,d=CH 77 Repeater +f=477362500,m=NFM,bw=8k5,d=CH 78 Repeater +f=477387500,m=NFM,bw=8k5,d=CH 79 Gen Chat +f=477412500,m=NFM,bw=8k5,d=CH 80 Gen Chat \ No newline at end of file diff --git a/sdcard/LOOKINGGLASS/PRESETS.TXT b/sdcard/LOOKINGGLASS/PRESETS.TXT index 4fbf7062b..8114eb7a2 100644 --- a/sdcard/LOOKINGGLASS/PRESETS.TXT +++ b/sdcard/LOOKINGGLASS/PRESETS.TXT @@ -25,6 +25,8 @@ 1879,1931,DECT # FRS/GMRS 462,468,FRS/GMRS +# AUS UHF CB +476,478,AUS UHF CB # HAM RADIO 28,30,HAM 10-METER 50,54,HAM 6-METER From 2dca408e45579237d97638d662318c228f021f07 Mon Sep 17 00:00:00 2001 From: Totoo Date: Fri, 29 Mar 2024 01:25:23 +0100 Subject: [PATCH 73/98] Wardrive Map app (#2050) * WardriveMap app * better txt * Count only displayed markers --- firmware/application/external/external.cmake | 5 + firmware/application/external/external.ld | 7 + .../external/foxhunt/ui_foxhunt_rx.cpp | 3 +- .../application/external/wardrivemap/main.cpp | 82 ++++++++++ .../external/wardrivemap/ui_wardrivemap.cpp | 143 ++++++++++++++++++ .../external/wardrivemap/ui_wardrivemap.hpp | 85 +++++++++++ 6 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 firmware/application/external/wardrivemap/main.cpp create mode 100644 firmware/application/external/wardrivemap/ui_wardrivemap.cpp create mode 100644 firmware/application/external/wardrivemap/ui_wardrivemap.hpp diff --git a/firmware/application/external/external.cmake b/firmware/application/external/external.cmake index 120e58db4..c8c3878b7 100644 --- a/firmware/application/external/external.cmake +++ b/firmware/application/external/external.cmake @@ -76,6 +76,10 @@ set(EXTCPPSRC #audio_test external/audio_test/main.cpp external/audio_test/ui_audio_test.cpp + + #wardrivemap + external/wardrivemap/main.cpp + external/wardrivemap/ui_wardrivemap.cpp ) set(EXTAPPLIST @@ -97,4 +101,5 @@ set(EXTAPPLIST extsensors foxhunt_rx audio_test + wardrivemap ) diff --git a/firmware/application/external/external.ld b/firmware/application/external/external.ld index 4e3f12682..d42fee550 100644 --- a/firmware/application/external/external.ld +++ b/firmware/application/external/external.ld @@ -41,6 +41,7 @@ MEMORY ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k ram_external_app_foxhunt_rx(rwx) : org = 0xADC00000, len = 32k ram_external_app_audio_test(rwx) : org = 0xADC10000, len = 32k + ram_external_app_wardrivemap(rwx) : org = 0xADC20000, len = 32k } SECTIONS @@ -153,4 +154,10 @@ SECTIONS *(*ui*external_app*audio_test*); } > ram_external_app_audio_test + .external_app_wardrivemap : ALIGN(4) SUBALIGN(4) + { + KEEP(*(.external_app.app_wardrivemap.application_information)); + *(*ui*external_app*wardrivemap*); + } > ram_external_app_wardrivemap + } diff --git a/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp b/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp index cac19c305..3c8bfb11e 100644 --- a/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp +++ b/firmware/application/external/foxhunt/ui_foxhunt_rx.cpp @@ -62,8 +62,7 @@ FoxhuntRxView::FoxhuntRxView(NavigationView& nav) }; geomap.set_mode(DISPLAY); geomap.set_manual_panning(false); - // geomap.set_enable_additional_zoom(true); - // geomap.set_hide_center_marker(true); //todo hide again after testing + // geomap.set_hide_center_marker(true); //todo test if needed geomap.set_focusable(true); geomap.clear_markers(); receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); diff --git a/firmware/application/external/wardrivemap/main.cpp b/firmware/application/external/wardrivemap/main.cpp new file mode 100644 index 000000000..fb5fb7eb6 --- /dev/null +++ b/firmware/application/external/wardrivemap/main.cpp @@ -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_wardrivemap.hpp" +#include "ui_navigation.hpp" +#include "external_app.hpp" + +namespace ui::external_app::wardrivemap { +void initialize_app(ui::NavigationView& nav) { + nav.push(); +} +} // namespace ui::external_app::wardrivemap + +extern "C" { + +__attribute__((section(".external_app.app_wardrivemap.application_information"), used)) application_information_t _application_information_wardrivemap = { + /*.memory_location = */ (uint8_t*)0x00000000, + /*.externalAppEntry = */ ui::external_app::wardrivemap::initialize_app, + /*.header_version = */ CURRENT_HEADER_VERSION, + /*.app_version = */ VERSION_MD5, + + /*.app_name = */ "WardriveMap", + /*.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::yellow().v, + /*.menu_location = */ app_location_t::UTILITIES, + + /*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0}, + /*.m4_app_offset = */ 0x00000000, // will be filled at compile time +}; +} diff --git a/firmware/application/external/wardrivemap/ui_wardrivemap.cpp b/firmware/application/external/wardrivemap/ui_wardrivemap.cpp new file mode 100644 index 000000000..39052b3da --- /dev/null +++ b/firmware/application/external/wardrivemap/ui_wardrivemap.cpp @@ -0,0 +1,143 @@ +/* + * 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_wardrivemap.hpp" + +#include "rtc_time.hpp" +#include "string_format.hpp" +#include "file_path.hpp" +#include "metadata_file.hpp" +#include "portapack_persistent_memory.hpp" + +using namespace portapack; +using namespace ui; + +namespace ui::external_app::wardrivemap { + +void WardriveMapView::focus() { + geopos.focus(); +} + +// needs to load on every map change, because won't store or draw all while marker is not in the current view. +// todo optimize this somehow +bool WardriveMapView::load_markers() { + uint16_t cnt = 0; + uint16_t displayed_cnt = 0; + geomap.clear_markers(); + // serach for files with geotag, and add it to geomap as marker with tag. limit to N bc of mem limit. + for (const auto& entry : std::filesystem::directory_iterator(captures_dir, u"*.txt")) { + if (std::filesystem::is_regular_file(entry.status())) { + if (displayed_cnt > 30) break; + std::filesystem::path pth = captures_dir; + pth += u"/" + entry.path(); + auto metadata_path = get_metadata_path(pth); + auto metadata = read_metadata_file(metadata_path); + + if (metadata) { + if (metadata.value().latitude != 0 && metadata.value().longitude != 0 && metadata.value().latitude < 400 && metadata.value().longitude < 400) { + if (first_init == false) { + // move map there before add, so will display this. + geopos.set_report_change(false); + geopos.set_lat(metadata.value().latitude); + geopos.set_lon(metadata.value().longitude); + geopos.set_report_change(true); + geomap.move(metadata.value().longitude, metadata.value().latitude); + first_init = true; + } + GeoMarker tmp{metadata.value().latitude, metadata.value().longitude, 400, entry.path().filename().string()}; + if (geomap.store_marker(tmp) == MapMarkerStored::MARKER_STORED) displayed_cnt++; + cnt++; + } + } + } + } + return (cnt > 0); +} + +WardriveMapView::WardriveMapView(NavigationView& nav) + : nav_{nav} { + add_children({&text_info, + &geomap, + &geopos, + &text_notfound}); + + geomap.set_mode(DISPLAY); + geomap.set_manual_panning(false); + geomap.set_focusable(true); + geomap.set_hide_center_marker(true); + geomap.clear_markers(); + + geopos.set_report_change(false); + geopos.set_lat(0); + geopos.set_lon(0); + geopos.set_altitude(0); + geopos.set_speed(0); + geopos.set_read_only(true); + geopos.hide_altandspeed(); + geopos.set_report_change(true); + + geopos.on_change = [this](int32_t altitude, float lat, float lon, int32_t speed) { + (void)altitude; + (void)speed; + geomap.set_manual_panning(true); + geomap.move(lon, lat); + load_markers(); + geomap.set_dirty(); + }; + text_notfound.hidden(true); + geomap.init(); + // load markers + if (load_markers()) { + text_notfound.hidden(true); + geomap.set_dirty(); + } else { + geomap.hidden(true); + geopos.hidden(true); + } + geomap.on_move = [this](float lon, float lat) { + (void)lon; + (void)lat; + load_markers(); + }; +} + +WardriveMapView::~WardriveMapView() { +} + +void WardriveMapView::on_gps(const GPSPosDataMessage* msg) { + geomap.update_my_position(msg->lat, msg->lon, msg->altitude); + if (geomap.manual_panning() == false) { + geopos.set_report_change(false); + geopos.set_lat(msg->lat); + geopos.set_lon(msg->lon); + geopos.set_altitude(msg->altitude); + geopos.set_speed(msg->speed); + geopos.set_report_change(true); + geomap.move(msg->lon, msg->lat); + load_markers(); + } + geomap.set_dirty(); +} + +void WardriveMapView::on_orientation(const OrientationDataMessage* msg) { + geomap.set_angle(msg->angle); + geomap.update_my_orientation(msg->angle, true); +} + +} // namespace ui::external_app::wardrivemap \ No newline at end of file diff --git a/firmware/application/external/wardrivemap/ui_wardrivemap.hpp b/firmware/application/external/wardrivemap/ui_wardrivemap.hpp new file mode 100644 index 000000000..8ec9f5701 --- /dev/null +++ b/firmware/application/external/wardrivemap/ui_wardrivemap.hpp @@ -0,0 +1,85 @@ +/* + * 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_WARDRIVEMAP_H__ +#define __UI_WARDRIVEMAP_H__ + +#include "ui.hpp" +#include "ui_language.hpp" +#include "ui_navigation.hpp" +#include "ui_geomap.hpp" +#include "app_settings.hpp" +#include "utility.hpp" + +using namespace ui; + +namespace ui::external_app::wardrivemap { + +class WardriveMapView : public View { + public: + WardriveMapView(NavigationView& nav); + ~WardriveMapView(); + + void focus() override; + + std::string title() const override { + return "WardriveMap"; + }; + + private: + NavigationView& nav_; + + Text text_info{{0 * 8, 0 * 8, 30 * 8, 16 * 1}, "All GEOTAG from CAPTURES"}; + Text text_notfound{{0 * 8, 3 * 8, 30 * 8, 16 * 1}, "No GeoTagged captures found"}; + GeoPos geopos{ + {0, 20}, + GeoPos::alt_unit::METERS, + GeoPos::spd_unit::HIDDEN}; + GeoMap geomap{{0, 75, 240, 320 - 75}}; + + void on_gps(const GPSPosDataMessage* msg); + void on_orientation(const OrientationDataMessage* msg); + + bool load_markers(); // returns true if any exists, false if none. + + bool first_init = false; + + MessageHandlerRegistration message_handler_gps{ + Message::ID::GPSPosData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_gps(message); + }}; + MessageHandlerRegistration message_handler_orientation{ + Message::ID::OrientationData, + [this](Message* const p) { + const auto message = static_cast(p); + this->on_orientation(message); + }}; +}; +}; // namespace ui::external_app::wardrivemap + +#endif /*__UI_WARDRIVEMAP_H__*/ From 2e1e02baac9addea17f050e7de6c72f91b860135 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Thu, 28 Mar 2024 21:04:19 -0500 Subject: [PATCH 74/98] Removed special font characters (#2056) --- sdcard/FREQMAN/POCSAG.TXT | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sdcard/FREQMAN/POCSAG.TXT b/sdcard/FREQMAN/POCSAG.TXT index 9fdadd525..273fd5806 100644 --- a/sdcard/FREQMAN/POCSAG.TXT +++ b/sdcard/FREQMAN/POCSAG.TXT @@ -5,20 +5,20 @@ f=466075000,d=FRA e-Msg3 1200 f=466175000,d=FRA e-Msg4 1200 f=466206250,d=FRA e-Msg5 1200 f=466231250,d=FRA e-Msg6 1200 -f=173512500,d=FRA Fire * -f=85955000,d=FRA Fire HF -f=173550000,d=FRA Fire 1 -f=173625000,d=FRA Fire 2 -f=173550000,d=FRA Fire 3 -f=173700000,d=FRA Fire 4 -f=173875000,d=FRA Fire 5 -f=173925000,d=FRA Fire 6 -f=173550000,d=FRA Fire 7 -f=168950000,d=FRA Fire 8 -f=169025000,d=FRA Fire 9 -f=169100000,d=FRA Fire 10 -f=169275000,d=FRA Fire 11 -f=169325000,d=FRA Fire 12 +f=173512500,d=FRA Fire * +f=85955000,d=FRA Fire HF +f=173550000,d=FRA Fire 1 +f=173625000,d=FRA Fire 2 +f=173550000,d=FRA Fire 3 +f=173700000,d=FRA Fire 4 +f=173875000,d=FRA Fire 5 +f=173925000,d=FRA Fire 6 +f=173550000,d=FRA Fire 7 +f=168950000,d=FRA Fire 8 +f=169025000,d=FRA Fire 9 +f=169100000,d=FRA Fire 10 +f=169275000,d=FRA Fire 11 +f=169325000,d=FRA Fire 12 f=446475000,d=FRA Priv1 f=446525000,d=FRA Priv2 f=448425000,d=GER Fire 1200 From 90ff1e62ce0c8c3189884ce9e382b5bb8e797b36 Mon Sep 17 00:00:00 2001 From: set sail into the sea of life <24917424+zxkmm@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:05:09 +0800 Subject: [PATCH 75/98] move the no ext app tile to forward (#2047) * strong notice of missing ext app * textual * move the notice tile to front and remove the painter string * remove notice icon * format * for back button * remove <> --- firmware/application/ui/ui_btngrid.cpp | 14 ++++++++++++++ firmware/application/ui/ui_btngrid.hpp | 1 + firmware/application/ui_navigation.cpp | 21 +++++++++++---------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index 740276126..1277fce1c 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2019 Elia Yehuda (z4ziggy) * Copyright (C) 2023 Mark Thompson * Copyright (C) 2024 u-foka + * Copyleft (ↄ) 2024 zxkmm with the GPL license * * This file is part of PortaPack. * @@ -133,6 +134,19 @@ void BtnGridView::add_item(GridItem new_item) { } } +void BtnGridView::insert_item(GridItem new_item, uint8_t position) { + if (!blacklisted_app(new_item)) { + if (position < menu_items.size()) { + auto pos_iter = menu_items.begin() + position; + menu_items.insert(pos_iter, new_item); + update_items(); + } else { + menu_items.push_back(new_item); + update_items(); + } + } +} + void BtnGridView::update_items() { size_t i = 0; Color bg_color = portapack::persistent_memory::menu_color(); diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp index 2256f7665..6cea1996d 100644 --- a/firmware/application/ui/ui_btngrid.hpp +++ b/firmware/application/ui/ui_btngrid.hpp @@ -61,6 +61,7 @@ class BtnGridView : public View { void add_items(std::initializer_list new_items); void add_item(GridItem new_item); + void insert_item(GridItem new_item, uint8_t position); void set_max_rows(int rows); int rows(); void clear(); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index a48924385..9b0d84ab2 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -723,16 +723,17 @@ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc) void addExternalItems(NavigationView& nav, app_location_t location, BtnGridView& grid) { auto externalItems = ExternalItemsMenuLoader::load_external_items(location, nav); if (externalItems.empty()) { - grid.add_item({"Notice", - Color::red(), - &bitmap_icon_debug, - [&nav]() { - nav.display_modal( - "Notice", - "External app directory empty;\n" - "see Mayhem wiki and copy apps\n" - "to " + apps_dir.string() + " folder of SD card."); - }}); + grid.insert_item({"Notice!", + Color::red(), + nullptr, + [&nav]() { + nav.display_modal( + "Notice", + "External app directory empty;\n" + "see Mayhem wiki and copy apps\n" + "to " + apps_dir.string() + " folder of SD card."); + }}, + pmem::show_gui_return_icon() ? 1 : 0); } else { for (auto const& gridItem : externalItems) { grid.add_item(gridItem); From ba36680a7bd9da1e90adfa6ac25be252a17f708b Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 04:44:37 -0500 Subject: [PATCH 76/98] FileMan support for folder Cut & Paste and Timestamp Rename (#2055) --- firmware/application/apps/ui_fileman.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 9d33be043..28dc5c550 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -514,7 +514,10 @@ void FileManagerView::on_paste() { fs::filesystem_error result; if (clipboard_mode == ClipboardMode::Cut) - result = rename_file(clipboard_path, current_path / new_name); + if ((current_path / clipboard_path.filename()) == clipboard_path) + result = FR_OK; // Skip paste to avoid renaming if path is unchanged + else + result = rename_file(clipboard_path, current_path / new_name); else if (clipboard_mode == ClipboardMode::Copy) result = copy_file(clipboard_path, current_path / new_name); @@ -639,7 +642,7 @@ FileManagerView::FileManagerView( }; button_cut.on_select = [this]() { - if (selected_is_valid() && !get_selected_entry().is_directory) { + if (selected_is_valid()) { clipboard_path = get_selected_full_path(); clipboard_mode = ClipboardMode::Cut; } else @@ -658,7 +661,7 @@ FileManagerView::FileManagerView( if (clipboard_mode != ClipboardMode::None) on_paste(); else - nav_.display_modal("Paste", "Cut or copy a file first."); + nav_.display_modal("Paste", " Cut or copy a file,\n or cut a folder, first."); }; button_new_dir.on_select = [this]() { @@ -678,7 +681,7 @@ FileManagerView::FileManagerView( }; button_rename_timestamp.on_select = [this]() { - if (selected_is_valid() && !get_selected_entry().is_directory) { + if (selected_is_valid()) { on_rename(::truncate(to_string_timestamp(rtc_time::now()), 8)); } else nav_.display_modal("Timestamp Rename", "Can't rename that."); From fe2fbb847f607aaf3d7f0154fdd0ff2fcb229881 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:26:45 -0500 Subject: [PATCH 77/98] Beep-on-packets option in Settings and updated ERT & Sonde apps (#2058) * Beep-on-packets option in Settings * Add beep to ERT app --- firmware/application/apps/ert_app.cpp | 15 ++++++++++++++- firmware/application/apps/ert_app.hpp | 3 +++ firmware/application/apps/ui_settings.cpp | 4 ++++ firmware/application/apps/ui_settings.hpp | 11 ++++++++++- firmware/application/apps/ui_sonde.cpp | 16 ++++++---------- firmware/application/apps/ui_sonde.hpp | 7 ------- firmware/baseband/proc_audio_beep.hpp | 2 -- firmware/baseband/proc_ert.cpp | 11 +++++++++++ firmware/baseband/proc_ert.hpp | 2 ++ firmware/common/portapack_persistent_memory.cpp | 11 ++++++++++- firmware/common/portapack_persistent_memory.hpp | 2 ++ 11 files changed, 62 insertions(+), 22 deletions(-) diff --git a/firmware/application/apps/ert_app.cpp b/firmware/application/apps/ert_app.cpp index 26b6f7357..3cb7f71e5 100644 --- a/firmware/application/apps/ert_app.cpp +++ b/firmware/application/apps/ert_app.cpp @@ -23,7 +23,7 @@ #include "ert_app.hpp" #include "baseband_api.hpp" - +#include "audio.hpp" #include "portapack.hpp" using namespace portapack; @@ -33,6 +33,8 @@ using namespace portapack; #include "string_format.hpp" #include "file_path.hpp" +namespace pmem = portapack::persistent_memory; + namespace ert { namespace format { @@ -121,6 +123,7 @@ ERTAppView::ERTAppView(NavigationView& nav) &field_lna, &field_vga, &rssi, + &field_volume, &recent_entries_view, }); @@ -132,9 +135,15 @@ ERTAppView::ERTAppView(NavigationView& nav) if (logger) { logger->append(logs_dir / u"ERT.TXT"); } + + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } } ERTAppView::~ERTAppView() { + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); } @@ -158,6 +167,10 @@ void ERTAppView::on_packet(const ert::Packet& packet) { entry.update(packet); recent_entries_view.set_dirty(); } + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } void ERTAppView::on_show_list() { diff --git a/firmware/application/apps/ert_app.hpp b/firmware/application/apps/ert_app.hpp index 93bfa5150..283ca3209 100644 --- a/firmware/application/apps/ert_app.hpp +++ b/firmware/application/apps/ert_app.hpp @@ -165,6 +165,9 @@ class ERTAppView : public View { {21 * 8, 0, 6 * 8, 4}, }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + MessageHandlerRegistration message_handler_packet{ Message::ID::ERTPacket, [this](Message* const p) { diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 9f6c7fc43..bdfff1419 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -635,13 +635,17 @@ void SetPersistentMemoryView::focus() { SetAudioView::SetAudioView(NavigationView& nav) { add_children({&labels, &field_tone_mix, + &checkbox_beep_on_packets, &button_save, &button_cancel}); field_tone_mix.set_value(pmem::tone_mix()); + checkbox_beep_on_packets.set_value(pmem::beep_on_packets()); + button_save.on_select = [&nav, this](Button&) { pmem::set_tone_mix(field_tone_mix.value()); + pmem::set_beep_on_packets(checkbox_beep_on_packets.value()); audio::output::update_audio_mute(); nav.pop(); }; diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 77fc3a784..00292a0a8 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -506,8 +506,12 @@ class SetAudioView : public View { Labels labels{ {{1 * 8, 1 * 16}, "Controls the volume of the", Color::light_grey()}, {{1 * 8, 2 * 16}, "tone when transmitting in", Color::light_grey()}, - {{1 * 8, 3 * 16}, "Soundboard or Mic apps.", Color::light_grey()}, + {{1 * 8, 3 * 16}, "Soundboard or Mic apps:", Color::light_grey()}, {{2 * 8, 5 * 16}, "Tone key mix: %", Color::light_grey()}, + {{1 * 8, 8 * 16}, "Controls whether apps should", Color::light_grey()}, + {{1 * 8, 9 * 16}, "beep on speaker & headphone", Color::light_grey()}, + {{1 * 8, 10 * 16}, "when a packet is received", Color::light_grey()}, + {{1 * 8, 11 * 16}, "(not all apps support this):", Color::light_grey()}, }; NumberField field_tone_mix{ @@ -517,6 +521,11 @@ class SetAudioView : public View { 1, '0'}; + Checkbox checkbox_beep_on_packets{ + {3 * 8, 13 * 16}, + 16, + "Beep on RX packets"}; + Button button_save{ {2 * 8, 16 * 16, 12 * 8, 32}, "Save"}; diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index 281acd0e4..0a8c576e1 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -32,6 +32,7 @@ #include using namespace portapack; +namespace pmem = portapack::persistent_memory; #include "string_format.hpp" #include "complex.hpp" @@ -54,7 +55,6 @@ SondeView::SondeView(NavigationView& nav) &field_vga, &rssi, &field_volume, - &check_beep, &check_log, &check_crc, &text_signature, @@ -72,13 +72,6 @@ SondeView::SondeView(NavigationView& nav) geopos.set_read_only(true); - check_beep.set_value(beep); - check_beep.on_select = [this](Checkbox&, bool v) { - beep = v; - if (beep) - baseband::request_audio_beep(1000, 24000, 60); // 1khz tone for 60ms to acknowledge enablement - }; - check_log.set_value(logging); check_log.on_select = [this](Checkbox&, bool v) { logging = v; @@ -115,7 +108,10 @@ SondeView::SondeView(NavigationView& nav) if (logger) logger->append(logs_dir / u"SONDE.TXT"); - audio::output::start(); + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } // inject a PitchRSSIConfigureMessage in order to arm // the pitch rssi events that will be used by the @@ -185,7 +181,7 @@ void SondeView::on_packet(const sonde::Packet& packet) { logger->on_packet(packet); } - if (beep) { + if (pmem::beep_on_packets()) { baseband::request_rssi_beep(); } } diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index 100eadfe6..bbf50929d 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -75,14 +75,12 @@ class SondeView : public View { 1750000 /* bandwidth */, 2457600 /* sampling rate */ }; - bool beep{false}; bool logging{false}; bool use_crc{false}; app_settings::SettingsManager settings_{ "rx_sonde", app_settings::Mode::RX, { - {"beep"sv, &beep}, {"logging"sv, &logging}, {"use_crc"sv, &use_crc}, }}; @@ -124,11 +122,6 @@ class SondeView : public View { AudioVolumeField field_volume{ {28 * 8, 0 * 16}}; - Checkbox check_beep{ - {22 * 8, 6 * 16}, - 3, - "Beep"}; - Checkbox check_log{ {22 * 8, 8 * 16}, 3, diff --git a/firmware/baseband/proc_audio_beep.hpp b/firmware/baseband/proc_audio_beep.hpp index 68166b910..a803d9581 100644 --- a/firmware/baseband/proc_audio_beep.hpp +++ b/firmware/baseband/proc_audio_beep.hpp @@ -25,8 +25,6 @@ #include "baseband_processor.hpp" #include "message.hpp" -#define AUDIO_SAMPLE_RATE 24000 - class AudioBeepProcessor : public BasebandProcessor { public: AudioBeepProcessor(); diff --git a/firmware/baseband/proc_ert.cpp b/firmware/baseband/proc_ert.cpp index 908f0f94e..7a142c2dd 100644 --- a/firmware/baseband/proc_ert.cpp +++ b/firmware/baseband/proc_ert.cpp @@ -21,6 +21,7 @@ */ #include "proc_ert.hpp" +#include "audio_dma.hpp" #include "portapack_shared_memory.hpp" @@ -109,7 +110,17 @@ void ERTProcessor::idm_handler( shared_memory.application_queue.push(message); } +void ERTProcessor::on_message(const Message* const msg) { + if (msg->id == Message::ID::AudioBeep) + on_beep_message(*reinterpret_cast(msg)); +} + +void ERTProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_ert.hpp b/firmware/baseband/proc_ert.hpp index 480e010ee..355a05794 100644 --- a/firmware/baseband/proc_ert.hpp +++ b/firmware/baseband/proc_ert.hpp @@ -102,6 +102,8 @@ class ERTProcessor : public BasebandProcessor { void scm_handler(const baseband::Packet& packet); void scmplus_handler(const baseband::Packet& packet); void idm_handler(const baseband::Packet& packet); + void on_message(const Message* const msg); + void on_beep_message(const AudioBeepMessage& message); float sum_half_period[2]; float sum_period[3]; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 4fe7aa62a..70ec98048 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -152,7 +152,7 @@ struct misc_config_t { bool config_disable_external_tcxo : 1; bool config_sdcard_high_speed_io : 1; bool config_disable_config_mode : 1; - bool UNUSED_5 : 1; + bool beep_on_packets : 1; bool UNUSED_6 : 1; bool UNUSED_7 : 1; @@ -641,6 +641,10 @@ bool config_disable_config_mode() { return data->misc_config.config_disable_config_mode; } +bool beep_on_packets() { + return data->misc_config.beep_on_packets; +} + bool config_sdcard_high_speed_io() { return data->misc_config.config_sdcard_high_speed_io; } @@ -718,6 +722,10 @@ void set_config_disable_config_mode(bool v) { data->misc_config.config_disable_config_mode = v; } +void set_beep_on_packets(bool v) { + data->misc_config.beep_on_packets = v; +} + void set_config_sdcard_high_speed_io(bool v, bool save) { if (v) { /* 200MHz / (2 * 2) = 50MHz */ @@ -1247,6 +1255,7 @@ bool debug_dump() { pmem_dump_file.write_line("misc_config config_disable_external_tcxo: " + to_string_dec_uint(config_disable_external_tcxo())); pmem_dump_file.write_line("misc_config config_sdcard_high_speed_io: " + to_string_dec_uint(config_sdcard_high_speed_io())); pmem_dump_file.write_line("misc_config config_disable_config_mode: " + to_string_dec_uint(config_disable_config_mode())); + pmem_dump_file.write_line("misc_config beep_on_packets: " + to_string_dec_int(beep_on_packets())); // receiver_model pmem_dump_file.write_line("\n[Receiver Model]"); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 397c79aba..a34973ef8 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -204,6 +204,7 @@ void set_config_cpld(uint8_t i); bool config_disable_external_tcxo(); bool config_sdcard_high_speed_io(); bool config_disable_config_mode(); +bool beep_on_packets(); bool config_splash(); bool config_converter(); @@ -226,6 +227,7 @@ void set_show_bigger_qr_code(bool v); void set_config_disable_external_tcxo(bool v); void set_config_sdcard_high_speed_io(bool v, bool save); void set_config_disable_config_mode(bool v); +void set_beep_on_packets(bool v); void set_config_splash(bool v); bool config_converter(); From 0db65ccb6be824c33fd045e93c8d40a8821439f2 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:27:53 -0500 Subject: [PATCH 78/98] Beep-on-packet support in POCSAG app (#2061) --- firmware/application/apps/pocsag_app.cpp | 8 ++++++++ firmware/baseband/proc_pocsag2.cpp | 8 ++++++++ firmware/baseband/proc_pocsag2.hpp | 1 + 3 files changed, 17 insertions(+) diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index 5d0533e4d..3879c8e80 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -136,6 +136,10 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) }; refresh_ui(); + + if (pmem::beep_on_packets()) + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); receiver_model.enable(); baseband::set_pocsag(); @@ -304,6 +308,10 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { // Set status icon color to indicate state machine state. image_status.set_foreground(get_status_color(pocsag_state)); + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } void POCSAGAppView::on_stats(const POCSAGStatsMessage* stats) { diff --git a/firmware/baseband/proc_pocsag2.cpp b/firmware/baseband/proc_pocsag2.cpp index 1170a520b..65dd7b096 100644 --- a/firmware/baseband/proc_pocsag2.cpp +++ b/firmware/baseband/proc_pocsag2.cpp @@ -361,6 +361,10 @@ void POCSAGProcessor::on_message(const Message* const message) { break; } + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(message)); + break; + default: break; } @@ -414,6 +418,10 @@ void POCSAGProcessor::send_packet() { shared_memory.application_queue.push(message); } +void POCSAGProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + /* main **************************************************/ int main() { diff --git a/firmware/baseband/proc_pocsag2.hpp b/firmware/baseband/proc_pocsag2.hpp index d7ca21189..9215e7fd3 100644 --- a/firmware/baseband/proc_pocsag2.hpp +++ b/firmware/baseband/proc_pocsag2.hpp @@ -212,6 +212,7 @@ class POCSAGProcessor : public BasebandProcessor { void reset(); void send_stats() const; void send_packet(); + void on_beep_message(const AudioBeepMessage& message); /* Set once app is ready to receive messages. */ bool configured = false; From 746bf1c15f89624011692a0cf04a382a8a3cd8a4 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:28:27 -0500 Subject: [PATCH 79/98] Beep-on-packet support in TPMS app (#2062) * Beep-on-packet support in TPMS app * audio::output::stop when exiting --- firmware/application/apps/tpms_app.cpp | 15 ++++++++++++++- firmware/application/apps/tpms_app.hpp | 3 +++ firmware/baseband/proc_tpms.cpp | 11 +++++++++++ firmware/baseband/proc_tpms.hpp | 3 +++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/firmware/application/apps/tpms_app.cpp b/firmware/application/apps/tpms_app.cpp index bf9f14f8e..06cf1c370 100644 --- a/firmware/application/apps/tpms_app.cpp +++ b/firmware/application/apps/tpms_app.cpp @@ -23,7 +23,7 @@ #include "tpms_app.hpp" #include "baseband_api.hpp" - +#include "audio.hpp" #include "portapack.hpp" using namespace portapack; @@ -32,6 +32,8 @@ using namespace portapack; #include "utility.hpp" #include "file_path.hpp" +namespace pmem = portapack::persistent_memory; + namespace tpms { namespace format { @@ -147,6 +149,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { baseband::run_image(portapack::spi_flash::image_tag_tpms); add_children({&rssi, + &field_volume, &channel, &options_band, &options_pressure, @@ -179,9 +182,15 @@ TPMSAppView::TPMSAppView(NavigationView&) { if (logger) { logger->append(logs_dir / u"TPMS.TXT"); } + + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } } TPMSAppView::~TPMSAppView() { + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); } @@ -214,6 +223,10 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) { entry.update(reading); recent_entries_view.set_dirty(); } + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } void TPMSAppView::on_show_list() { diff --git a/firmware/application/apps/tpms_app.hpp b/firmware/application/apps/tpms_app.hpp index d4beb8312..06d93003d 100644 --- a/firmware/application/apps/tpms_app.hpp +++ b/firmware/application/apps/tpms_app.hpp @@ -143,6 +143,9 @@ class TPMSAppView : public View { {21 * 8, 0, 6 * 8, 4}, }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + Channel channel{ {21 * 8, 5, 6 * 8, 4}, }; diff --git a/firmware/baseband/proc_tpms.cpp b/firmware/baseband/proc_tpms.cpp index bd604231c..2cae8a248 100644 --- a/firmware/baseband/proc_tpms.cpp +++ b/firmware/baseband/proc_tpms.cpp @@ -21,6 +21,7 @@ */ #include "proc_tpms.hpp" +#include "audio_dma.hpp" #include "dsp_fir_taps.hpp" @@ -60,7 +61,17 @@ void TPMSProcessor::execute(const buffer_c8_t& buffer) { } } +void TPMSProcessor::on_message(const Message* const msg) { + if (msg->id == Message::ID::AudioBeep) + on_beep_message(*reinterpret_cast(msg)); +} + +void TPMSProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_tpms.hpp b/firmware/baseband/proc_tpms.hpp index c755a6777..6fcf1d62a 100644 --- a/firmware/baseband/proc_tpms.hpp +++ b/firmware/baseband/proc_tpms.hpp @@ -140,6 +140,9 @@ class TPMSProcessor : public BasebandProcessor { shared_memory.application_queue.push(message); }}; + void on_message(const Message* const message); + void on_beep_message(const AudioBeepMessage& message); + /* NB: Threads should be the last members in the class definition. */ BasebandThread baseband_thread{ baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false}; From f1ebb1a6e3abe306017db8431f84fcf53ef703fa Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:29:50 -0500 Subject: [PATCH 80/98] Beep-on-packet support in Weather app (#2063) --- .../application/apps/ui_weatherstation.cpp | 13 ++++++++++++ .../application/apps/ui_weatherstation.hpp | 4 ++++ firmware/baseband/proc_weather.cpp | 20 +++++++++++++++++-- firmware/baseband/proc_weather.hpp | 1 + 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/firmware/application/apps/ui_weatherstation.cpp b/firmware/application/apps/ui_weatherstation.cpp index e277696be..06ae180fb 100644 --- a/firmware/application/apps/ui_weatherstation.cpp +++ b/firmware/application/apps/ui_weatherstation.cpp @@ -30,6 +30,8 @@ using namespace portapack; using namespace ui; +namespace pmem = portapack::persistent_memory; + namespace ui { void WeatherRecentEntryDetailView::update_data() { @@ -91,6 +93,7 @@ WeatherView::WeatherView(NavigationView& nav) &field_rf_amp, &field_lna, &field_vga, + &field_volume, &field_frequency, &options_temperature, &button_clear_list, @@ -120,6 +123,11 @@ WeatherView::WeatherView(NavigationView& nav) signal_token_tick_second = rtc_time::signal_tick_second += [this]() { on_tick_second(); }; + + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } } void WeatherView::on_tick_second() { @@ -142,10 +150,15 @@ void WeatherView::on_data(const WeatherDataMessage* data) { truncate_entries(recent, 64); } recent_entries_view.set_dirty(); + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } WeatherView::~WeatherView() { rtc_time::signal_tick_second -= signal_token_tick_second; + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); } diff --git a/firmware/application/apps/ui_weatherstation.hpp b/firmware/application/apps/ui_weatherstation.hpp index a0b8f0e9e..c31bf6289 100644 --- a/firmware/application/apps/ui_weatherstation.hpp +++ b/firmware/application/apps/ui_weatherstation.hpp @@ -126,6 +126,10 @@ class WeatherView : public View { {18 * 8, 0 * 16}}; RSSI rssi{ {21 * 8, 0, 6 * 8, 4}}; + + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + RxFrequencyField field_frequency{ {0 * 8, 0 * 16}, nav_}; diff --git a/firmware/baseband/proc_weather.cpp b/firmware/baseband/proc_weather.cpp index 99b7489f8..3d661c60b 100644 --- a/firmware/baseband/proc_weather.cpp +++ b/firmware/baseband/proc_weather.cpp @@ -23,6 +23,7 @@ #include "proc_weather.hpp" #include "portapack_shared_memory.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" void WeatherProcessor::execute(const buffer_c8_t& buffer) { if (!configured) return; @@ -66,8 +67,18 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) { } void WeatherProcessor::on_message(const Message* const message) { - if (message->id == Message::ID::SubGhzFPRxConfigure) - configure(*reinterpret_cast(message)); + switch (message->id) { + case Message::ID::SubGhzFPRxConfigure: + configure(*reinterpret_cast(message)); + break; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(message)); + break; + + default: + break; + } } void WeatherProcessor::configure(const SubGhzFPRxConfigureMessage& message) { @@ -84,7 +95,12 @@ void WeatherProcessor::configure(const SubGhzFPRxConfigureMessage& message) { configured = true; } +void WeatherProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_weather.hpp b/firmware/baseband/proc_weather.hpp index dc3824c7f..c668f604a 100644 --- a/firmware/baseband/proc_weather.hpp +++ b/firmware/baseband/proc_weather.hpp @@ -66,6 +66,7 @@ class WeatherProcessor : public BasebandProcessor { FProtoListGeneral* protoList = new WeatherProtos(); // holds all the protocols we can parse void configure(const SubGhzFPRxConfigureMessage& message); + void on_beep_message(const AudioBeepMessage& message); /* NB: Threads should be the last members in the class definition. */ BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive}; From 76017c91a9e7924e9afb779aa853f6d074aeae84 Mon Sep 17 00:00:00 2001 From: Dumpster-Diver <85180967+Dumpster-Diver@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:52:00 +0100 Subject: [PATCH 81/98] Create RADIOS_FM_FR_PARIS.TXT with FM Radios in Paris (#2049) * Create RADIOS_FM_FR.TXT with FM Radios in Paris This new file will add FM frequencies for France. As a start it covers Paris FM radio frequencies. It is based on https://www.csa.fr/maradiofm/liste_ville?recherche=3&commune=Paris * Update and rename RADIOS_FM_FR.TXT to RADIOS_FM_FR_PARIS.TXT Reduce frequency description length to fit under the 30 chars limit --- sdcard/FREQMAN/RADIOS_FM_FR_PARIS.TXT | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 sdcard/FREQMAN/RADIOS_FM_FR_PARIS.TXT diff --git a/sdcard/FREQMAN/RADIOS_FM_FR_PARIS.TXT b/sdcard/FREQMAN/RADIOS_FM_FR_PARIS.TXT new file mode 100644 index 000000000..a8cf24c41 --- /dev/null +++ b/sdcard/FREQMAN/RADIOS_FM_FR_PARIS.TXT @@ -0,0 +1,56 @@ +f=87800000,m=WFM,bw=200k,d=France Inter +f=87600000,m=WFM,bw=200k,d=France Inter +f=88200000,m=WFM,bw=200k,d=Generations +f=88600000,m=WFM,bw=200k,d=Radio Soleil +f=89000000,m=WFM,bw=200k,d=RFI +f=89400000,m=WFM,bw=200k,d=Radio Libertaire +f=89900000,m=WFM,bw=200k,d=TSF Jazz +f=90400000,m=WFM,bw=200k,d=Nostalgie +f=90900000,m=WFM,bw=200k,d=Chante France +f=91300000,m=WFM,bw=200k,d=Cherie FM +f=91700000,m=WFM,bw=200k,d=France Musique +f=92100000,m=WFM,bw=200k,d=Mouv' +f=92600000,m=WFM,bw=200k,d=Tropiques FM +f=93100000,m=WFM,bw=200k,d=Cause Commune +f=93100000,m=WFM,bw=200k,d=Aligre FM +f=93500000,m=WFM,bw=200k,d=France Culture +f=93900000,m=WFM,bw=200k,d=Vivre FM +f=93900000,m=WFM,bw=200k,d=Radio Campus +f=94300000,m=WFM,bw=200k,d=Radio Orient +f=94800000,m=WFM,bw=200k,d=Radio Shalom +f=94800000,m=WFM,bw=200k,d=Radio J +f=94800000,m=WFM,bw=200k,d=RCJ +f=95200000,m=WFM,bw=200k,d=Ici Et Maintenant +f=95200000,m=WFM,bw=200k,d=Neo +f=95600000,m=WFM,bw=200k,d=Radio Courtoisie +f=96000000,m=WFM,bw=200k,d=Skyrock +f=96400000,m=WFM,bw=200k,d=BFM Business +f=96900000,m=WFM,bw=200k,d=Voltage +f=97400000,m=WFM,bw=200k,d=Rire Et Chansons +f=97800000,m=WFM,bw=200k,d=Ado +f=98200000,m=WFM,bw=200k,d=Radio FG +f=98600000,m=WFM,bw=200k,d=Radio Alfa +f=99000000,m=WFM,bw=200k,d=Latina +f=99500000,m=WFM,bw=200k,d=AYP FM +f=99500000,m=WFM,bw=200k,d=France Maghreb 2 +f=99900000,m=WFM,bw=200k,d=Sud Radio + +f=100300000,m=WFM,bw=200k,d=NRJ +f=100700000,m=WFM,bw=200k,d=Frequence Protestante +f=100700000,m=WFM,bw=200k,d=Radio Notre-Dame +f=101100000,m=WFM,bw=200k,d=Radio Classique +f=101500000,m=WFM,bw=200k,d=Radio Nova +f=101900000,m=WFM,bw=200k,d=Fun Radio +f=102300000,m=WFM,bw=200k,d=Oui FM +f=102700000,m=WFM,bw=200k,d=M Radio +f=103100000,m=WFM,bw=200k,d=RMC +f=103500000,m=WFM,bw=200k,d=Europe 2 +f=103900000,m=WFM,bw=200k,d=RFM +f=104300000,m=WFM,bw=200k,d=RTL +f=104700000,m=WFM,bw=200k,d=Europe 1 +f=105100000,m=WFM,bw=200k,d=FIP +f=105500000,m=WFM,bw=200k,d=France Info +f=105900000,m=WFM,bw=200k,d=RTL2 +f=106300000,m=WFM,bw=200k,d=Frequence Paris Plurielle +f=106700000,m=WFM,bw=200k,d=Beur FM +f=107100000,m=WFM,bw=200k,d=France Bleu +f=107500000,m=WFM,bw=200k,d=Africa Radio From 6e5eadd25cf6d0736bb1be75a096cf4bb067a0ae Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:08:32 -0500 Subject: [PATCH 82/98] Beep-on-packet support in AIS app (#2064) * Beep-on-packet support in AIS app --- firmware/application/apps/ais_app.cpp | 14 ++++++++++++++ firmware/application/apps/ais_app.hpp | 3 +++ firmware/baseband/proc_ais.cpp | 11 +++++++++++ firmware/baseband/proc_ais.hpp | 8 +++++--- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/firmware/application/apps/ais_app.cpp b/firmware/application/apps/ais_app.cpp index 0be21bdac..3e28fb4e8 100644 --- a/firmware/application/apps/ais_app.cpp +++ b/firmware/application/apps/ais_app.cpp @@ -20,6 +20,7 @@ */ #include "ais_app.hpp" +#include "audio.hpp" #include "string_format.hpp" #include "database.hpp" @@ -32,6 +33,8 @@ using namespace portapack; #include +namespace pmem = portapack::persistent_memory; + namespace ais { namespace format { @@ -190,6 +193,10 @@ void AISLogger::on_packet(const ais::Packet& packet) { } log_file.write_entry(packet.received_at(), entry); + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } void AISRecentEntry::update(const ais::Packet& packet) { @@ -377,6 +384,7 @@ AISAppView::AISAppView(NavigationView& nav) &field_lna, &field_vga, &rssi, + &field_volume, &channel, &recent_entries_view, &recent_entry_detail_view, @@ -402,9 +410,15 @@ AISAppView::AISAppView(NavigationView& nav) if (logger) { logger->append(logs_dir / u"AIS.TXT"); } + + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } } AISAppView::~AISAppView() { + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); } diff --git a/firmware/application/apps/ais_app.hpp b/firmware/application/apps/ais_app.hpp index 175ef4632..17aa700d5 100644 --- a/firmware/application/apps/ais_app.hpp +++ b/firmware/application/apps/ais_app.hpp @@ -209,6 +209,9 @@ class AISAppView : public View { {21 * 8, 0, 6 * 8, 4}, }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + Channel channel{ {21 * 8, 5, 6 * 8, 4}, }; diff --git a/firmware/baseband/proc_ais.cpp b/firmware/baseband/proc_ais.cpp index 6bb4a4aa0..d5b2ed860 100644 --- a/firmware/baseband/proc_ais.cpp +++ b/firmware/baseband/proc_ais.cpp @@ -20,6 +20,7 @@ */ #include "proc_ais.hpp" +#include "audio_dma.hpp" #include "portapack_shared_memory.hpp" @@ -64,7 +65,17 @@ void AISProcessor::payload_handler( shared_memory.application_queue.push(message); } +void AISProcessor::on_message(const Message* const message) { + if (message->id == Message::ID::AudioBeep) + on_beep_message(*reinterpret_cast(message)); +} + +void AISProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_ais.hpp b/firmware/baseband/proc_ais.hpp index e6e2727dd..93c4ef353 100644 --- a/firmware/baseband/proc_ais.hpp +++ b/firmware/baseband/proc_ais.hpp @@ -74,13 +74,15 @@ class AISProcessor : public BasebandProcessor { this->payload_handler(packet); }}; + void consume_symbol(const float symbol); + void payload_handler(const baseband::Packet& packet); + void on_message(const Message* const message); + void on_beep_message(const AudioBeepMessage& message); + /* NB: Threads should be the last members in the class definition. */ BasebandThread baseband_thread{ baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false}; RSSIThread rssi_thread{}; - - void consume_symbol(const float symbol); - void payload_handler(const baseband::Packet& packet); }; #endif /*__PROC_AIS_H__*/ From b473930f94ea7a11b17c0d64b508b69effdfe279 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:34:18 -0500 Subject: [PATCH 83/98] Beep-on-packet support in ADSB RX app (#2065) --- firmware/application/apps/ui_adsb_rx.cpp | 16 ++++++++++++++- firmware/application/apps/ui_adsb_rx.hpp | 9 ++++++--- firmware/baseband/proc_adsbrx.cpp | 25 +++++++++++++++++++----- firmware/baseband/proc_adsbrx.hpp | 2 ++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index 9fb60cd84..596734f85 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -32,9 +32,12 @@ #include "rtc_time.hpp" #include "string_format.hpp" #include "file_path.hpp" +#include "audio.hpp" using namespace portapack; +namespace pmem = portapack::persistent_memory; + namespace ui { static std::string get_map_tag(const AircraftRecentEntry& entry) { @@ -373,7 +376,8 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { &rssi, &recent_entries_view, &status_frame, - &status_good_frame}); + &status_good_frame, + &field_volume}); recent_entries_view.set_parent_rect({0, 16, 240, 272}); recent_entries_view.on_select = [this, &nav](const AircraftRecentEntry& entry) { @@ -395,10 +399,16 @@ ADSBRxView::ADSBRxView(NavigationView& nav) { receiver_model.enable(); baseband::set_adsb(); + + if (pmem::beep_on_packets()) { + audio::set_rate(audio::Rate::Hz_24000); + audio::output::start(); + } } ADSBRxView::~ADSBRxView() { rtc_time::signal_tick_second -= signal_token_tick_second; + audio::output::stop(); receiver_model.disable(); baseband::shutdown(); } @@ -473,6 +483,10 @@ void ADSBRxView::on_frame(const ADSBFrameMessage* message) { } logger->log(log_entry); + + if (pmem::beep_on_packets()) { + baseband::request_audio_beep(1000, 24000, 60); + } } void ADSBRxView::on_tick_second() { diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index 3e3f6e15d..329bbc456 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -421,19 +421,22 @@ class ADSBRxView : public View { {18 * 8, 0 * 16}}; RSSI rssi{ - {20 * 8, 4, 10 * 7, 8}, + {20 * 8, 4, 7 * 8, 8}, }; ActivityDot status_frame{ - {screen_width - 3, 5, 2, 2}, + {27 * 8 + 2, 5, 2, 2}, Color::white(), }; ActivityDot status_good_frame{ - {screen_width - 3, 9, 2, 2}, + {27 * 8 + 2, 9, 2, 2}, Color::green(), }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; + MessageHandlerRegistration message_handler_frame{ Message::ID::ADSBFrame, [this](Message* const p) { diff --git a/firmware/baseband/proc_adsbrx.cpp b/firmware/baseband/proc_adsbrx.cpp index 19abe04ea..2b5c5cf83 100644 --- a/firmware/baseband/proc_adsbrx.cpp +++ b/firmware/baseband/proc_adsbrx.cpp @@ -26,6 +26,7 @@ #include "portapack_shared_memory.hpp" #include "sine_table_int8.hpp" #include "event_m4.hpp" +#include "audio_dma.hpp" #include #include @@ -144,16 +145,30 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) { } void ADSBRXProcessor::on_message(const Message* const message) { - if (message->id == Message::ID::ADSBConfigure) { - bit_count = 0; - sample_count = 0; - decoding = false; - configured = true; + switch (message->id) { + case Message::ID::ADSBConfigure: + bit_count = 0; + sample_count = 0; + decoding = false; + configured = true; + break; + + case Message::ID::AudioBeep: + on_beep_message(*reinterpret_cast(message)); + break; + + default: + break; } } +void ADSBRXProcessor::on_beep_message(const AudioBeepMessage& message) { + audio::dma::beep_start(message.freq, message.sample_rate, message.duration_ms); +} + #ifndef _WIN32 int main() { + audio::dma::init_audio_out(); EventDispatcher event_dispatcher{std::make_unique()}; event_dispatcher.run(); return 0; diff --git a/firmware/baseband/proc_adsbrx.hpp b/firmware/baseband/proc_adsbrx.hpp index c96e596ce..3e65a345a 100644 --- a/firmware/baseband/proc_adsbrx.hpp +++ b/firmware/baseband/proc_adsbrx.hpp @@ -53,6 +53,8 @@ class ADSBRXProcessor : public BasebandProcessor { uint32_t shifter[ADSB_PREAMBLE_LENGTH + 1]; + void on_beep_message(const AudioBeepMessage& message); + /* NB: Threads should be the last members in the class definition. */ BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive}; RSSIThread rssi_thread{}; From cb9fee8f086f8d8fff9e09306b4a0e3767d36274 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:50:28 -0500 Subject: [PATCH 84/98] Modify warning text (#2066) --- firmware/tools/make_spi_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/tools/make_spi_image.py b/firmware/tools/make_spi_image.py index 38e9e68bc..2e72498e4 100755 --- a/firmware/tools/make_spi_image.py +++ b/firmware/tools/make_spi_image.py @@ -92,7 +92,7 @@ for i in range(0, len(spi_image), 4): val = int.from_bytes(snippet, byteorder='little') checksum += val if (val >= external_apps_address_start) and (val < external_apps_address_end) and ((val & 0xFFFF) < maximum_application_size): - print ("WARNING: External code address", hex(val), "at offset", hex(i), "in", sys.argv[3]) + print ("WARNING: Possible external code address", hex(val), "at offset", hex(i), "in", sys.argv[3]) final_checksum = 0 checksum = (final_checksum - checksum) & 0xFFFFFFFF From 2acefee4d2fc63e9eed8caf7fb70ba3af36427c9 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:34:37 +0100 Subject: [PATCH 85/98] adjust GUI for more preset name room (#2068) --- firmware/application/apps/ui_looking_glass_app.cpp | 10 +++++----- firmware/application/apps/ui_looking_glass_app.hpp | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/firmware/application/apps/ui_looking_glass_app.cpp b/firmware/application/apps/ui_looking_glass_app.cpp index 5679c5a0c..903f52a42 100644 --- a/firmware/application/apps/ui_looking_glass_app.cpp +++ b/firmware/application/apps/ui_looking_glass_app.cpp @@ -50,12 +50,12 @@ int32_t GlassView::map(int32_t value, int32_t fromLow, int32_t fromHigh, int32_t void GlassView::update_display_beep() { if (beep_enabled) { button_beep_squelch.set_style(&Styles::green); - // - button_beep_squelch.set_text("[bip>" + to_string_dec_int(beep_squelch, 4) + "db]"); + // bip-XXdb + button_beep_squelch.set_text("bip" + to_string_dec_int(beep_squelch, 3) + "db"); receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // WM8731 hack. } else { button_beep_squelch.set_style(&Styles::white); - button_beep_squelch.set_text("[ beep OFF ]"); + button_beep_squelch.set_text("bip OFF "); } } @@ -548,8 +548,8 @@ GlassView::GlassView( button_beep_squelch.on_change = [this]() { int new_beep_squelch = beep_squelch + button_beep_squelch.get_encoder_delta(); - if (new_beep_squelch < -100) - new_beep_squelch = -100; + if (new_beep_squelch < -99) + new_beep_squelch = -99; if (new_beep_squelch > 20) new_beep_squelch = 20; beep_squelch = new_beep_squelch; diff --git a/firmware/application/apps/ui_looking_glass_app.hpp b/firmware/application/apps/ui_looking_glass_app.hpp index a19dd1e99..9d6568ebe 100644 --- a/firmware/application/apps/ui_looking_glass_app.hpp +++ b/firmware/application/apps/ui_looking_glass_app.hpp @@ -173,7 +173,7 @@ class GlassView : public View { Labels labels{ {{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, 2 * 16}, "P:", Color::light_grey()}, {{0, 3 * 16}, "MARKER: MHz RXIQCAL", Color::light_grey()}, //{{0, 4 * 16}, "RES: STEPS:", Color::light_grey()}}; {{0, 4 * 16}, "RES: VOL:", Color::light_grey()}}; @@ -215,12 +215,12 @@ class GlassView : public View { {28 * 8, 1 * 16}}; OptionsField range_presets{ - {7 * 8, 2 * 16}, - 10, + {2 * 8, 2 * 16}, + 20, {}}; ButtonWithEncoder button_beep_squelch{ - {18 * 8, 2 * 16 + 4, 12 * 8, 1 * 8}, + {240 - 8 * 8, 2 * 16 + 4, 8 * 8, 1 * 8}, ""}; TextField field_marker{ From 6d9d5ad1af46099b1068e03b62ae50dcdf7013dc Mon Sep 17 00:00:00 2001 From: sommermorgentraum <24917424+zxkmm@users.noreply.github.com> Date: Sat, 30 Mar 2024 20:03:27 +0800 Subject: [PATCH 86/98] fix read file (#2070) --- firmware/application/apps/ui_recon_settings.cpp | 4 ++-- firmware/application/apps/ui_scanner.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/application/apps/ui_recon_settings.cpp b/firmware/application/apps/ui_recon_settings.cpp index b5e7be347..3cfd5e42c 100644 --- a/firmware/application/apps/ui_recon_settings.cpp +++ b/firmware/application/apps/ui_recon_settings.cpp @@ -59,7 +59,7 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st auto open_view = nav.push(".TXT"); open_view->push_dir(freqman_dir); open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) { - if (new_file_path.native().find(freqman_dir.native()) == 0) { + if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) { _input_file = new_file_path.stem().string(); text_input_file.set(_input_file); } else { @@ -72,7 +72,7 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st auto open_view = nav.push(".TXT"); open_view->push_dir(freqman_dir); open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) { - if (new_file_path.native().find(freqman_dir.native()) == 0) { + if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) { _output_file = new_file_path.stem().string(); button_choose_output_name.set_text(_output_file); } else { diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index e6a3c819c..8f7d4495c 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -338,7 +338,7 @@ ScannerView::ScannerView( auto open_view = nav.push(".TXT"); open_view->push_dir(freqman_dir); open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) { - if (new_file_path.native().find(freqman_dir.native()) == 0) { + if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) { scan_pause(); frequency_file_load(new_file_path); } else { From d29172f41eb73fae35a2418d5710a3325806e846 Mon Sep 17 00:00:00 2001 From: Totoo Date: Sat, 30 Mar 2024 16:48:45 +0100 Subject: [PATCH 87/98] Add GPS icon, fix overwrite bug (#2072) --- firmware/application/ui_record_view.cpp | 22 ++++++++++++++-------- firmware/application/ui_record_view.hpp | 6 ++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 236910447..f83a94117 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -75,6 +75,7 @@ RecordView::RecordView( &rect_background, //&button_pitch_rssi, &button_record, + &gps_icon, &text_record_filename, &text_record_dropped, &text_time_available, @@ -93,6 +94,7 @@ RecordView::RecordView( signal_token_tick_second = rtc_time::signal_tick_second += [this]() { this->on_tick_second(); }; + gps_icon.hidden(true); } RecordView::~RecordView() { @@ -180,6 +182,13 @@ void RecordView::start() { } std::filesystem::path base_path; + + auto tmp_path = filename_stem_pattern; // store it, to be able to modify without causing permanent change + // check for geo data, if present append filename with _GEO + if (latitude != 0 && longitude != 0 && latitude < 200 && longitude < 200) { + tmp_path.append_filename(u"_GEO"); + } + if (filename_date_frequency) { rtc_time::now(datetime); @@ -192,24 +201,19 @@ void RecordView::start() { to_string_dec_uint(datetime.minute()) + to_string_dec_uint(datetime.second()); - base_path = filename_stem_pattern.string() + "_" + date_time + "_" + + base_path = tmp_path.string() + "_" + date_time + "_" + trim(to_string_freq(receiver_model.target_frequency())) + "Hz"; base_path = folder / base_path; } else if (filename_as_is) { - base_path = filename_stem_pattern.string(); + base_path = tmp_path.string(); base_path = folder / base_path; } else - base_path = next_filename_matching_pattern(folder / filename_stem_pattern); + base_path = next_filename_matching_pattern(folder / tmp_path); if (base_path.empty()) { 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 writer; switch (file_type) { case FileType::WAV: { @@ -348,6 +352,8 @@ void RecordView::trim_capture() { } void RecordView::on_gps(const GPSPosDataMessage* msg) { + if (msg->lat == 0 || msg->lat > 399) return; // not valid one + if (latitude == 0) gps_icon.hidden(false); // prev was 0, so not shown already latitude = msg->lat; longitude = msg->lon; satinuse = msg->satinuse; diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 9d94d5cff..68c57d57c 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -144,6 +144,12 @@ class RecordView : public View { "", }; + Image gps_icon{ + {2 * 8 + 1, 0 * 16, 2 * 8, 1 * 16}, + &bitmap_target, + Color::white(), + Color::black()}; + std::unique_ptr capture_thread{}; MessageHandlerRegistration message_handler_capture_thread_error{ From 56303eb385dd7b466eff8b09ea0d0d30a2aa462d Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Sat, 30 Mar 2024 12:57:43 -0500 Subject: [PATCH 88/98] Use freq from AppSettings unless passed from another app (#2073) --- firmware/application/app_settings.cpp | 8 ++------ firmware/application/app_settings.hpp | 3 --- firmware/application/apps/analog_audio_app.cpp | 2 ++ firmware/application/apps/analog_audio_app.hpp | 1 - firmware/application/apps/capture_app.cpp | 8 ++++++++ firmware/application/apps/capture_app.hpp | 4 ++-- firmware/application/apps/ui_mictx.cpp | 2 ++ firmware/application/apps/ui_mictx.hpp | 1 - firmware/application/apps/ui_recon.cpp | 4 ++-- firmware/application/apps/ui_scanner.cpp | 2 +- firmware/application/receiver_model.cpp | 1 + firmware/application/receiver_model.hpp | 1 + 12 files changed, 21 insertions(+), 16 deletions(-) diff --git a/firmware/application/app_settings.cpp b/firmware/application/app_settings.cpp index ce067e4c2..505ed456c 100644 --- a/firmware/application/app_settings.cpp +++ b/firmware/application/app_settings.cpp @@ -175,16 +175,12 @@ void copy_to_radio_model(const AppSettings& settings) { // Specifically 'modulation' which requires a running baseband. if (flags_enabled(settings.mode, Mode::TX)) { - if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency)) - persistent_memory::set_target_frequency(settings.tx_frequency); - + persistent_memory::set_target_frequency(settings.tx_frequency); transmitter_model.configure_from_app_settings(settings); } if (flags_enabled(settings.mode, Mode::RX)) { - if (!flags_enabled(settings.options, Options::UseGlobalTargetFrequency)) - persistent_memory::set_target_frequency(settings.rx_frequency); - + persistent_memory::set_target_frequency(settings.rx_frequency); receiver_model.configure_from_app_settings(settings); receiver_model.set_configuration_without_update( static_cast(settings.modulation), diff --git a/firmware/application/app_settings.hpp b/firmware/application/app_settings.hpp index 422daaa36..dd83c405e 100644 --- a/firmware/application/app_settings.hpp +++ b/firmware/application/app_settings.hpp @@ -118,9 +118,6 @@ enum class Mode : uint8_t { enum class Options { None = 0x0000, - - /* Don't use target frequency from app settings. */ - UseGlobalTargetFrequency = 0x0001, }; /* NB: See RX/TX model headers for default values. */ diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index 2be1ccd4f..c055539a9 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -208,7 +208,9 @@ AnalogAudioView::AnalogAudioView( NavigationView& nav, ReceiverModel::settings_t override) : AnalogAudioView(nav) { + // Settings to override when launched from another app (versus from AppSettings .ini file) // TODO: Which other settings make sense to override? + field_frequency.set_value(override.frequency_app_override); on_frequency_step_changed(override.frequency_step); options_modulation.set_by_value(toUType(override.mode)); } diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index 56da85404..efe154c7a 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -174,7 +174,6 @@ class AnalogAudioView : public View { app_settings::SettingsManager settings_{ "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. }}; diff --git a/firmware/application/apps/capture_app.cpp b/firmware/application/apps/capture_app.cpp index 999d4176e..a774a2c1f 100644 --- a/firmware/application/apps/capture_app.cpp +++ b/firmware/application/apps/capture_app.cpp @@ -104,6 +104,14 @@ CaptureAppView::CaptureAppView(NavigationView& nav) }; } +CaptureAppView::CaptureAppView( + NavigationView& nav, + ReceiverModel::settings_t override) + : CaptureAppView(nav) { + // Settings to override when launched from another app (versus from AppSettings .ini file) + field_frequency.set_value(override.frequency_app_override); +} + CaptureAppView::~CaptureAppView() { receiver_model.disable(); baseband::shutdown(); diff --git a/firmware/application/apps/capture_app.hpp b/firmware/application/apps/capture_app.hpp index 07a162b40..bec009ac6 100644 --- a/firmware/application/apps/capture_app.hpp +++ b/firmware/application/apps/capture_app.hpp @@ -38,6 +38,7 @@ namespace ui { class CaptureAppView : public View { public: CaptureAppView(NavigationView& nav); + CaptureAppView(NavigationView& nav, ReceiverModel::settings_t override); ~CaptureAppView(); void focus() override; @@ -52,8 +53,7 @@ class CaptureAppView : public View { NavigationView& nav_; RxRadioState radio_state_{ReceiverModel::Mode::Capture}; app_settings::SettingsManager settings_{ - "rx_capture", app_settings::Mode::RX, - app_settings::Options::UseGlobalTargetFrequency}; + "rx_capture", app_settings::Mode::RX}; Labels labels{ {{0 * 8, 1 * 16}, "Rate:", Color::light_grey()}, diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index e72e63a0a..005303dc4 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -596,6 +596,7 @@ MicTXView::MicTXView( NavigationView& nav, ReceiverModel::settings_t override) : MicTXView(nav) { + // Settings to override when launched from another app (versus from AppSettings .ini file) // Try to use the modulation/bandwidth from RX settings. // TODO: These concepts should be merged so there's only one. switch (override.mode) { @@ -616,6 +617,7 @@ MicTXView::MicTXView( break; } + field_frequency.set_value(override.frequency_app_override); check_common_freq_tx_rx.set_value(true); // freq passed from other app is in tx_frequency, so set rx_frequency=tx_frequency // TODO: bandwidth selection is tied too tightly to the UI diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 8a0c18c86..9b599b2bd 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -118,7 +118,6 @@ class MicTXView : public View { app_settings::SettingsManager settings_{ "tx_mic", app_settings::Mode::RX_TX, - app_settings::Options::UseGlobalTargetFrequency, { {"mic_mod_index"sv, &mic_mod_index}, {"rxbw_index"sv, &rxbw_index}, diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index afa3782f0..d3531b858 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -508,7 +508,7 @@ ReconView::ReconView(NavigationView& nav) auto settings = receiver_model.settings(); settings.frequency_step = step_mode.selected_index_value(); if (field_mode.selected_index_value() == SPEC_MODULATION) - nav_.replace(); + nav_.replace(settings); else nav_.replace(settings); }; @@ -539,7 +539,7 @@ ReconView::ReconView(NavigationView& nav) } } - // MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model. + // MicTX wants Frequency, Modulation and Bandwidth overrides, but that's only stored on the RX model. nav_.replace(receiver_model.settings()); }; diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 8f7d4495c..fc49f6646 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -413,7 +413,7 @@ ScannerView::ScannerView( button_mic_app.on_select = [this](Button&) { if (scan_thread) scan_thread->stop(); - // MicTX wants Modulation and Bandwidth overrides, but that's only stored on the RX model. + // MicTX wants Frequency, Modulation and Bandwidth overrides, but that's only stored on the RX model. nav_.replace(receiver_model.settings()); }; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 0c0044a22..f7c795555 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -68,6 +68,7 @@ rf::Frequency ReceiverModel::target_frequency() const { void ReceiverModel::set_target_frequency(rf::Frequency f) { persistent_memory::set_target_frequency(f); + settings_.frequency_app_override = f; update_tuning_frequency(); } diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index 7b5263d3a..ecdb32236 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -48,6 +48,7 @@ class ReceiverModel { uint32_t baseband_bandwidth = max283x::filter::bandwidth_minimum; uint32_t sampling_rate = 3'072'000; rf::Frequency frequency_step = 25'000; + rf::Frequency frequency_app_override = 0; uint8_t lna_gain_db = 32; uint8_t vga_gain_db = 32; bool rf_amp = false; From a30875b582030741785e8f1a5ae09abb389c2b8e Mon Sep 17 00:00:00 2001 From: Totoo Date: Tue, 2 Apr 2024 17:02:02 +0200 Subject: [PATCH 89/98] Fileman memory opt (#2076) * paginator * fixes * string instead of path, so saves ram. * fix FileLoadView * pagination list number * pagination "size" test * added detection of special folder name to display page numbers instead of (0 or a number of byte) * order of things: only one directory '..', only on first page Co-authored-by: gullradriel --- firmware/application/apps/ui_fileman.cpp | 178 +++++++++++++++++------ firmware/application/apps/ui_fileman.hpp | 17 ++- 2 files changed, 147 insertions(+), 48 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 28dc5c550..d2d0ab84f 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -62,7 +62,7 @@ std::string truncate(const fs::path& path, size_t max_length) { } // Inserts the entry into the entry list sorted directories first then by file name. -void insert_sorted(std::vector& entries, fileman_entry&& entry) { +void insert_sorted(std::list& entries, fileman_entry&& entry) { auto it = std::lower_bound( std::begin(entries), std::end(entries), entry, [](const fileman_entry& lhs, const fileman_entry& rhs) { @@ -149,31 +149,64 @@ namespace ui { void FileManBaseView::load_directory_contents(const fs::path& dir_path) { current_path = dir_path; entry_list.clear(); + menu_view.clear(); auto filtering = !extension_filter.empty(); bool cxx_file = path_iequal(cxx_ext, extension_filter); + bool wasfull = false; // reached the limit or not text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24)); for (const auto& entry : fs::directory_iterator(dir_path, u"*")) { // Hide files starting with '.' (hidden / tmp). + if (entry_list.size() >= max_items_loaded) { + wasfull = true; + break; // hard limit. size() complexyt constant in list from c++11, and for vector it constant. + } if (!show_hidden_files && is_hidden_file(entry.path())) continue; if (fs::is_regular_file(entry.status())) { if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path()))) - insert_sorted(entry_list, {entry.path(), (uint32_t)entry.size(), false}); + insert_sorted(entry_list, {entry.path().string(), (uint32_t)entry.size(), false}); } else if (fs::is_directory(entry.status())) { - insert_sorted(entry_list, {entry.path(), 0, true}); + insert_sorted(entry_list, {entry.path().string(), 0, true}); } } + // paginating + auto list_size = entry_list.size(); + nb_pages = 1 + (list_size / items_per_page); + size_t start = pagination * items_per_page; + size_t stop = start + items_per_page; + if (list_size > start) { + if (list_size < stop) + stop = list_size; + entry_list.erase(std::next(entry_list.begin(), stop), entry_list.end()); + entry_list.erase(entry_list.begin(), std::next(entry_list.begin(), start)); + } + // Add "parent" directory if not at the root. - if (!dir_path.empty()) - entry_list.insert(entry_list.begin(), {parent_dir_path, 0, true}); + if (!dir_path.empty() && pagination == 0) + entry_list.insert(entry_list.begin(), {parent_dir_path.string(), 0, true}); + + // add next page + if (list_size > start + items_per_page) { + entry_list.push_back({str_next, (uint32_t)pagination + 1, true}); + } else { + // add warning if reached limit + if (wasfull) { + entry_list.push_back({str_full, max_items_loaded, true}); + } + } + + // add prev page + if (pagination > 0) { + entry_list.insert(entry_list.begin(), {str_back, (uint32_t)pagination - 1, true}); + } } fs::path FileManBaseView::get_selected_full_path() const { - if (get_selected_entry().path == parent_dir_path) + if (get_selected_entry().path == parent_dir_path.string()) return current_path.parent_path(); return current_path / get_selected_entry().path; @@ -181,7 +214,10 @@ fs::path FileManBaseView::get_selected_full_path() const { const fileman_entry& FileManBaseView::get_selected_entry() const { // TODO: return reference to an "empty" entry on OOB? - return entry_list[menu_view.highlighted_index()]; + auto it = entry_list.begin(); + if (menu_view.highlighted_index() >= 1) std::advance(it, menu_view.highlighted_index()); + return *it; + // return entry_list[menu_view.highlighted_index()]; } FileManBaseView::FileManBaseView( @@ -230,7 +266,7 @@ void FileManBaseView::push_dir(const fs::path& path) { current_path /= path; saved_index_stack.push_back(menu_view.highlighted_index()); menu_view.set_highlighted(0); - reload_current(); + reload_current(true); } } @@ -239,29 +275,56 @@ void FileManBaseView::pop_dir() { return; current_path = current_path.parent_path(); - reload_current(); + reload_current(true); menu_view.set_highlighted(saved_index_stack.back()); saved_index_stack.pop_back(); } +std::string get_extension(std::string t) { + const auto index = t.find_last_of(u'.'); + if (index == t.npos) { + return {}; + } else { + return t.substr(index); + } +} + +std::string get_stem(std::string t) { + const auto index = t.find_last_of(u'.'); + if (index == t.npos) { + return t; + } else { + return t.substr(0, index); + } +} +std::string get_filename(std::string _s) { + const auto index = _s.find_last_of("/"); + if (index == _s.npos) { + return _s; + } else { + return _s.substr(index + 1); + } +} void FileManBaseView::refresh_list() { if (on_refresh_widgets) on_refresh_widgets(false); - auto prev_highlight = menu_view.highlighted_index(); + prev_highlight = menu_view.highlighted_index(); menu_view.clear(); for (const auto& entry : entry_list) { - auto entry_name = truncate(entry.path, 20); + auto entry_name = std::string{entry.path.length() <= 20 ? entry.path : entry.path.substr(0, 20)}; if (entry.is_directory) { - auto size_str = - (entry.path == parent_dir_path) - ? "" - : to_string_dec_uint(file_count(current_path / entry.path)); + std::string size_str{}; + if (entry.path == str_next || entry.path == str_back) { + size_str = to_string_dec_uint(1 + entry.size) + "/" + to_string_dec_uint(nb_pages); // show computed number of pages + } else { + size_str = (entry.path == parent_dir_path.string()) ? "" : to_string_dec_uint(file_count(current_path / entry.path)); + } menu_view.add_item( - {entry_name + std::string(21 - entry_name.length(), ' ') + size_str, + {entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str, ui::Color::yellow(), &bitmap_icon_dir, [this](KeyEvent key) { @@ -270,11 +333,11 @@ void FileManBaseView::refresh_list() { }}); } else { - const auto& assoc = get_assoc(entry.path.extension()); + const auto& assoc = get_assoc(get_extension(entry.path)); auto size_str = to_string_file_size(entry.size); menu_view.add_item( - {entry_name + std::string(21 - entry_name.length(), ' ') + size_str, + {entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str, assoc.color, assoc.icon, [this](KeyEvent key) { @@ -282,16 +345,13 @@ void FileManBaseView::refresh_list() { on_select_entry(key); }}); } - - // HACK: Should page menu items instead of limiting the number. - if (menu_view.item_count() >= max_items_shown) - break; } menu_view.set_highlighted(prev_highlight); } -void FileManBaseView::reload_current() { +void FileManBaseView::reload_current(bool reset_pagination) { + if (reset_pagination) pagination = 0; load_directory_contents(current_path); refresh_list(); } @@ -327,6 +387,21 @@ FileLoadView::FileLoadView( on_select_entry = [this](KeyEvent) { if (get_selected_entry().is_directory) { + if (get_selected_entry().path == str_full) { + return; + } + if (get_selected_entry().path == str_back) { + pagination--; + menu_view.set_highlighted(0); + reload_current(false); + return; + } + if (get_selected_entry().path == str_next) { + pagination++; + menu_view.set_highlighted(0); + reload_current(false); + return; + } push_dir(get_selected_entry().path); } else { if (on_changed) @@ -416,10 +491,10 @@ void FileManagerView::on_rename(std::string_view hint) { auto& entry = get_selected_entry(); // Append the hint to the filename stem as a rename suggestion. - name_buffer = entry.path.stem().string(); + name_buffer = get_stem(entry.path); if (!hint.empty()) name_buffer += "_" + std::string{hint}; - name_buffer += entry.path.extension().string(); + name_buffer += get_extension(entry.path); // Set the rename cursor to before the extension to make renaming simpler. uint32_t cursor_pos = (uint32_t)name_buffer.length(); @@ -440,11 +515,11 @@ void FileManagerView::on_rename(std::string_view hint) { auto new_name = renamed_path.replace_extension(partner.extension()); rename_file(partner, current_path / new_name); } - reload_current(); + reload_current(false); }); if (!has_partner) - reload_current(); + reload_current(false); }); } @@ -454,7 +529,7 @@ void FileManagerView::on_delete() { return; } - auto name = get_selected_entry().path.filename().string(); + auto name = get_filename(get_selected_entry().path); nav_.push( "Delete", "Delete " + name + "\nAre you sure?", YESNO, [this](bool choice) { @@ -466,11 +541,11 @@ void FileManagerView::on_delete() { [this](const fs::path& partner, bool should_delete) { if (should_delete) delete_file(partner); - reload_current(); + reload_current(true); }); if (!has_partner) - reload_current(); + reload_current(true); } }); } @@ -495,7 +570,7 @@ void FileManagerView::on_clean() { std::filesystem::path current_full_path = path_name / file_name; delete_file(current_full_path); } - reload_current(); + reload_current(true); } }); } @@ -504,7 +579,7 @@ void FileManagerView::on_new_dir() { name_buffer = ""; text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) { make_new_directory(current_path / dir_name); - reload_current(); + reload_current(true); }); } @@ -528,14 +603,14 @@ void FileManagerView::on_paste() { clipboard_path = fs::path{}; clipboard_mode = ClipboardMode::None; menu_view.focus(); - reload_current(); + reload_current(true); } void FileManagerView::on_new_file() { name_buffer = ""; text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& file_name) { make_new_file(current_path / file_name); - reload_current(); + reload_current(true); }); } @@ -558,7 +633,7 @@ bool FileManagerView::handle_file_open() { return true; } else if (path_iequal(bmp_ext, ext)) { nav_.push(path); - reload_current(); + reload_current(false); return true; } else if (path_iequal(rem_ext, ext)) { nav_.push(path); @@ -570,7 +645,7 @@ bool FileManagerView::handle_file_open() { bool FileManagerView::selected_is_valid() const { return !entry_list.empty() && - get_selected_entry().path != parent_dir_path; + get_selected_entry().path != parent_dir_path.string(); } FileManagerView::FileManagerView( @@ -602,7 +677,7 @@ FileManagerView::FileManagerView( }); menu_view.on_highlight = [this]() { - if (menu_view.highlighted_index() >= max_items_shown - 1) { + if (menu_view.highlighted_index() >= max_items_loaded - 1) { // todo check this if correct text_date.set_style(&Styles::red); text_date.set("Too many files!"); } else { @@ -617,13 +692,30 @@ FileManagerView::FileManagerView( refresh_list(); on_select_entry = [this](KeyEvent key) { - if (key == KeyEvent::Select && get_selected_entry().is_directory) { - push_dir(get_selected_entry().path); - } else if (key == KeyEvent::Select && handle_file_open()) { - return; - } else { - button_rename.focus(); + if (key == KeyEvent::Select) { + if (get_selected_entry().is_directory) { + if (get_selected_entry().path == str_full) { + return; + } + if (get_selected_entry().path == str_back) { + pagination--; + menu_view.set_highlighted(0); + reload_current(false); + return; + } + if (get_selected_entry().path == str_next) { + pagination++; + menu_view.set_highlighted(0); + reload_current(false); + return; + } + push_dir(get_selected_entry().path); + return; + } else if (handle_file_open()) { + return; + } } + button_rename.focus(); }; button_rename.on_select = [this]() { diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 06ee942c6..18c25d1fc 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -31,7 +31,7 @@ namespace ui { struct fileman_entry { - std::filesystem::path path{}; + std::string path{}; uint32_t size{}; bool is_directory{}; }; @@ -61,8 +61,12 @@ class FileManBaseView : public View { void push_dir(const std::filesystem::path& path); protected: - static constexpr size_t max_filename_length = 64; - static constexpr size_t max_items_shown = 100; + uint32_t prev_highlight = 0; + uint8_t pagination = 0; + uint8_t nb_pages = 1; + static constexpr size_t max_filename_length = 20; + static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't load more + static constexpr size_t items_per_page = 20; struct file_assoc_t { std::filesystem::path extension; @@ -87,7 +91,7 @@ class FileManBaseView : public View { void pop_dir(); void refresh_list(); - void reload_current(); + void reload_current(bool reset_pagination = false); void load_directory_contents(const std::filesystem::path& dir_path); const file_assoc_t& get_assoc(const std::filesystem::path& ext) const; @@ -97,11 +101,14 @@ class FileManBaseView : public View { std::function on_select_entry{nullptr}; std::function on_refresh_widgets{nullptr}; + const std::string str_back{"<--"}; + const std::string str_next{"-->"}; + const std::string str_full{"Can't load more.."}; const std::filesystem::path parent_dir_path{u".."}; std::filesystem::path current_path{u""}; std::filesystem::path extension_filter{u""}; - std::vector entry_list{}; + std::list entry_list{}; std::vector saved_index_stack{}; bool show_hidden_files{false}; From 804b7c87b7282a5a91b1ea3ae68a1365d9bec28f Mon Sep 17 00:00:00 2001 From: Totoo Date: Tue, 2 Apr 2024 20:19:28 +0200 Subject: [PATCH 90/98] allow to load more files but unordered (#2077) --- firmware/application/apps/ui_fileman.cpp | 84 ++++++++++++++++++++---- firmware/application/apps/ui_fileman.hpp | 4 +- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index d2d0ab84f..2ad716ad5 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -146,22 +146,89 @@ namespace ui { /* FileManBaseView ***********************************************************/ -void FileManBaseView::load_directory_contents(const fs::path& dir_path) { +void FileManBaseView::load_directory_contents_unordered(const fs::path& dir_path, size_t file_cnt) { + current_path = dir_path; + entry_list.clear(); + menu_view.clear(); + auto filtering = !extension_filter.empty(); + bool cxx_file = path_iequal(cxx_ext, extension_filter); + + text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24)); + + nb_pages = 1 + (file_cnt / items_per_page); + size_t start = pagination * items_per_page; + size_t stop = start + items_per_page; + if (file_cnt < stop) stop = file_cnt; + if (start > file_cnt) start = 0; // shouldn't hapen but check against it won't hurt + + size_t curr = 0; + + for (const auto& entry : fs::directory_iterator(dir_path, u"*")) { + if (entry_list.size() >= items_per_page) { + break; + } + // Hide files starting with '.' (hidden / tmp). + if (!show_hidden_files && is_hidden_file(entry.path())) + continue; + + if (fs::is_regular_file(entry.status())) { + if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path()))) { + curr++; + if (curr >= start) insert_sorted(entry_list, {entry.path().string(), (uint32_t)entry.size(), false}); + } + + } else if (fs::is_directory(entry.status())) { + curr++; + if (curr >= start) insert_sorted(entry_list, {entry.path().string(), 0, true}); + } + } + + // Add "parent" directory if not at the root. + if (!dir_path.empty() && pagination == 0) + entry_list.insert(entry_list.begin(), {parent_dir_path.string(), 0, true}); + + // add next page + if (file_cnt > start + items_per_page) { + entry_list.push_back({str_next, (uint32_t)pagination + 1, true}); + } + + // add prev page + if (pagination > 0) { + entry_list.insert(entry_list.begin(), {str_back, (uint32_t)pagination - 1, true}); + } +} + +int FileManBaseView::file_count_filtered(const fs::path& directory) { + int count{0}; + auto filtering = !extension_filter.empty(); + bool cxx_file = path_iequal(cxx_ext, extension_filter); + + for (auto& entry : std::filesystem::directory_iterator(directory, (const TCHAR*)u"*")) { + if (fs::is_regular_file(entry.status())) { + if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path()))) + ++count; + } else + ++count; + } + return count; +} + +void FileManBaseView::load_directory_contents(const fs::path& dir_path) { + size_t file_cnt = file_count_filtered(dir_path); + if (file_cnt >= max_items_loaded) { + load_directory_contents_unordered(dir_path, file_cnt); + return; + } current_path = dir_path; entry_list.clear(); menu_view.clear(); auto filtering = !extension_filter.empty(); bool cxx_file = path_iequal(cxx_ext, extension_filter); - bool wasfull = false; // reached the limit or not text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24)); for (const auto& entry : fs::directory_iterator(dir_path, u"*")) { // Hide files starting with '.' (hidden / tmp). - if (entry_list.size() >= max_items_loaded) { - wasfull = true; - break; // hard limit. size() complexyt constant in list from c++11, and for vector it constant. - } if (!show_hidden_files && is_hidden_file(entry.path())) continue; @@ -192,11 +259,6 @@ void FileManBaseView::load_directory_contents(const fs::path& dir_path) { // add next page if (list_size > start + items_per_page) { entry_list.push_back({str_next, (uint32_t)pagination + 1, true}); - } else { - // add warning if reached limit - if (wasfull) { - entry_list.push_back({str_full, max_items_loaded, true}); - } } // add prev page diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 18c25d1fc..0bbb5e78e 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -65,7 +65,7 @@ class FileManBaseView : public View { uint8_t pagination = 0; uint8_t nb_pages = 1; static constexpr size_t max_filename_length = 20; - static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't load more + static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't sort it static constexpr size_t items_per_page = 20; struct file_assoc_t { @@ -89,10 +89,12 @@ class FileManBaseView : public View { std::filesystem::path get_selected_full_path() const; const fileman_entry& get_selected_entry() const; + int file_count_filtered(const std::filesystem::path& directory); void pop_dir(); void refresh_list(); void reload_current(bool reset_pagination = false); void load_directory_contents(const std::filesystem::path& dir_path); + void load_directory_contents_unordered(const std::filesystem::path& dir_path, size_t file_cnt); const file_assoc_t& get_assoc(const std::filesystem::path& ext) const; NavigationView& nav_; From 3665b3c607283b501124f3a7ed1087384225946b Mon Sep 17 00:00:00 2001 From: Totoo Date: Wed, 3 Apr 2024 09:57:39 +0200 Subject: [PATCH 91/98] Added sil value ASDB (#2078) * Added sil value. resolves #2005 * readibility --- firmware/application/apps/ui_adsb_rx.cpp | 11 +++++++---- firmware/application/apps/ui_adsb_rx.hpp | 5 +++++ firmware/common/adsb_frame.hpp | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/firmware/application/apps/ui_adsb_rx.cpp b/firmware/application/apps/ui_adsb_rx.cpp index 596734f85..907717995 100644 --- a/firmware/application/apps/ui_adsb_rx.cpp +++ b/firmware/application/apps/ui_adsb_rx.cpp @@ -107,7 +107,8 @@ void ADSBLogger::log(const ADSBLogEntry& log_entry) { log_line += " Type:" + to_string_dec_uint(log_entry.vel_type) + " Hdg:" + to_string_dec_uint(log_entry.vel.heading) + " Spd: " + to_string_dec_int(log_entry.vel.speed); - + if (log_entry.sil != 0) + log_line += " Sil:" + to_string_dec_uint(log_entry.sil); log_file.write_entry(log_line); } @@ -354,11 +355,12 @@ void ADSBRxDetailsView::refresh_ui() { text_callsign.set(entry_.callsign); text_infos.set(entry_.info_string); + std::string str_sil = (entry_.sil > 0) ? " Sil:" + to_string_dec_uint(entry_.sil) : ""; if (entry_.velo.heading < 360 && entry_.velo.speed >= 0) text_info2.set("Hdg:" + to_string_dec_uint(entry_.velo.heading) + - " Spd:" + to_string_dec_int(entry_.velo.speed)); + " Spd:" + to_string_dec_int(entry_.velo.speed) + str_sil); else - text_info2.set(""); + text_info2.set(str_sil); text_frame_pos_even.set(to_string_hex_array(entry_.frame_pos_even.get_raw_data(), 14)); text_frame_pos_odd.set(to_string_hex_array(entry_.frame_pos_odd.get_raw_data(), 14)); @@ -471,7 +473,6 @@ void ADSBRxView::on_frame(const ADSBFrameMessage* message) { "Alt:" + to_string_dec_int(entry.pos.altitude) + " Lat:" + to_string_decimal(entry.pos.latitude, 2) + " Lon:" + to_string_decimal(entry.pos.longitude, 2); - entry.set_info_string(std::move(str_info)); } @@ -479,6 +480,8 @@ void ADSBRxView::on_frame(const ADSBFrameMessage* message) { entry.set_frame_velo(frame); log_entry.vel = entry.velo; log_entry.vel_type = msg_sub; + } else if (msg_type == AIRBORNE_OP_STATUS) { // for ver 1 + entry.sil = frame.get_sil_value(); } } diff --git a/firmware/application/apps/ui_adsb_rx.hpp b/firmware/application/apps/ui_adsb_rx.hpp index 329bbc456..46730c994 100644 --- a/firmware/application/apps/ui_adsb_rx.hpp +++ b/firmware/application/apps/ui_adsb_rx.hpp @@ -54,6 +54,8 @@ namespace ui { #define AIRBORNE_POS_GPS_L 20 // airborne position (lowest type id) #define AIRBORNE_POS_GPS_H 22 // airborne position (highest type id) +#define AIRBORNE_OP_STATUS 31 // Aircraft operation status + #define RESERVED_L 23 // reserved for other uses #define RESERVED_H 31 // reserved for other uses @@ -102,6 +104,8 @@ struct AircraftRecentEntry { std::string callsign{}; std::string info_string{}; + uint8_t sil{0}; // Surveillance integrity level + AircraftRecentEntry(const uint32_t ICAO_address) : ICAO_address{ICAO_address} { this->icao_str = to_string_hex(ICAO_address, 6); @@ -173,6 +177,7 @@ struct ADSBLogEntry { adsb_pos pos{}; adsb_vel vel{}; uint8_t vel_type{}; + uint8_t sil{}; }; // TODO: Make logging optional. diff --git a/firmware/common/adsb_frame.hpp b/firmware/common/adsb_frame.hpp index 83778ac90..1f05f744e 100644 --- a/firmware/common/adsb_frame.hpp +++ b/firmware/common/adsb_frame.hpp @@ -46,6 +46,10 @@ class ADSBFrame { return (raw_data[4] & 7); } + uint8_t get_sil_value() { + return ((raw_data[10] >> 6) & 0b11); // 83-84 bits + } + uint32_t get_ICAO_address() { return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3]; } From c48cbb7e55812ef31641b0cb4b3632ae0215269b Mon Sep 17 00:00:00 2001 From: Totoo Date: Wed, 3 Apr 2024 16:27:13 +0200 Subject: [PATCH 92/98] Autostart option (#2079) * Autostart app on boot * Settings page * ext app support --- firmware/application/apps/ui_settings.cpp | 57 +++++++++++++++++++++++ firmware/application/apps/ui_settings.hpp | 35 ++++++++++++++ firmware/application/main.cpp | 1 + firmware/application/ui_navigation.cpp | 21 +++++++++ firmware/application/ui_navigation.hpp | 2 + 5 files changed, 116 insertions(+) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index bdfff1419..92daf09f7 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -31,6 +31,7 @@ #include "ui_receiver.hpp" #include "ui_touch_calibration.hpp" #include "ui_text_editor.hpp" +#include "ui_external_items_menu_loader.hpp" #include "portapack_persistent_memory.hpp" #include "lpc43xx_cpp.hpp" @@ -839,6 +840,61 @@ void SetMenuColorView::focus() { button_save.focus(); } +/* SetAutostartView*/ +SetAutostartView::SetAutostartView(NavigationView& nav) { + add_children({&labels, + &button_save, + &button_cancel, + &options}); + + button_save.on_select = [&nav, this](Button&) { + nav_setting.save(); + nav.pop(); + }; + + button_cancel.on_select = [&nav, this](Button&) { + nav.pop(); + }; + + // options + i = 0; + OptionsField::option_t o{"-none-", i}; + opts.emplace_back(o); + for (auto& app : NavigationView::appList) { + if (app.id == nullptr) continue; + i++; + o = {app.displayName, i}; + opts.emplace_back(o); + full_app_list.emplace(i, app.id); + if (autostart_app == app.id) selected = i; + } + ExternalItemsMenuLoader::load_all_external_items_callback([this](ui::AppInfoConsole& app) { + if (app.appCallName == nullptr) return; + i++; + OptionsField::option_t o = {app.appFriendlyName, i}; + opts.emplace_back(o); + full_app_list.emplace(i, app.appCallName); + if (autostart_app == app.appCallName) selected = i; + }); + + options.set_options(opts); + options.on_change = [this](size_t, OptionsField::value_t v) { + if (v == 0) { + autostart_app = ""; + return; + } + auto it = full_app_list.find(v); + if (it != full_app_list.end()) { + autostart_app = it->second; + } + }; + options.set_selected_index(selected); +} + +void SetAutostartView::focus() { + options.focus(); +} + /* SettingsMenuView **************************************/ SettingsMenuView::SettingsMenuView(NavigationView& nav) @@ -866,6 +922,7 @@ void SettingsMenuView::on_populate() { //{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push(); }}, {"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, {"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, + {"Autostart", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, }); } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 00292a0a8..9a0aeff0b 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -799,6 +799,41 @@ class SetMenuColorView : public View { }; }; +class SetAutostartView : public View { + public: + SetAutostartView(NavigationView& nav); + + void focus() override; + + std::string title() const override { return "Autostart"; }; + + private: + int32_t i = 0; + std::string autostart_app{""}; + OptionsField::options_t opts; + std::map full_app_list; // looking table + int32_t selected = 0; + SettingsStore nav_setting{ + "nav"sv, + {{"autostart_app"sv, &autostart_app}}}; + Labels labels{ + {{1 * 8, 1 * 16}, "Select app to start on boot", Color::light_grey()}}; + + Button button_save{ + {2 * 8, 16 * 16, 12 * 8, 32}, + "Save"}; + + OptionsField options{ + {0 * 8, 3 * 16}, + 30, + {}}; + + Button button_cancel{ + {16 * 8, 16 * 16, 12 * 8, 32}, + "Cancel", + }; +}; + class SettingsMenuView : public BtnGridView { public: SettingsMenuView(NavigationView& nav); diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index dd8f0f160..4ec395cb3 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -158,6 +158,7 @@ static void event_loop() { event_dispatcher.set_display_sleep(true); }}; portapack::setEventDispatcherToUSBSerial(&event_dispatcher); + system_view.get_navigation_view()->handle_autostart(); event_dispatcher.run(); } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 9b0d84ab2..67c586363 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -107,6 +107,10 @@ #include "file_reader.hpp" #include "png_writer.hpp" #include "file_path.hpp" +#include "ff.h" + +#include +#include using portapack::receiver_model; using portapack::transmitter_model; @@ -708,6 +712,23 @@ bool NavigationView::set_on_pop(std::function on_pop) { return true; } +void NavigationView::handle_autostart() { + std::string autostart_app{""}; + SettingsStore nav_setting{ + "nav"sv, + {{"autostart_app"sv, &autostart_app}}}; + if (!autostart_app.empty()) { + if (StartAppByName(autostart_app.c_str())) return; + // if returned false, check for external apps by that name, and try to start it + std::string appwithpath = "/" + apps_dir.string() + "/"; + appwithpath += autostart_app; + appwithpath += ".ppma"; + std::wstring_convert, char16_t> conv; + std::filesystem::path pth = conv.from_bytes(appwithpath.c_str()); + ui::ExternalItemsMenuLoader::run_external_app(*this, pth); + } +} + /* Helpers **************************************************************/ static void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc) { diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 05576663e..8144efd48 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -136,6 +136,8 @@ class NavigationView : public View { static const AppList appList; bool StartAppByName(const char* name); // Starts a View (app) by name stored in appListFC. This is to start apps from console + void handle_autostart(); + private: struct ViewState { std::unique_ptr view; From 23cf1c2737bc0cc493884a79bd14324244e37571 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:17:48 +0200 Subject: [PATCH 93/98] fix build warning in settings (#2081) * fix warning ui::SetAutostartView::opts' should be initialized in the member initialization list * clang --------- Co-authored-by: gullradriel --- firmware/application/apps/ui_settings.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 9a0aeff0b..6e66ebf70 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -810,8 +810,8 @@ class SetAutostartView : public View { private: int32_t i = 0; std::string autostart_app{""}; - OptionsField::options_t opts; - std::map full_app_list; // looking table + OptionsField::options_t opts{}; + std::map full_app_list{}; // looking table int32_t selected = 0; SettingsStore nav_setting{ "nav"sv, From 689224fd8d6342b7d97cc47a3c862e464abb316d Mon Sep 17 00:00:00 2001 From: ImDroided Date: Fri, 5 Apr 2024 01:52:14 -0500 Subject: [PATCH 94/98] Added CubeSats to Presets --- sdcard/FREQMAN/SSTV.TXT | 2 +- sdcard/LOOKINGGLASS/PRESETS.TXT | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sdcard/FREQMAN/SSTV.TXT b/sdcard/FREQMAN/SSTV.TXT index db96dd650..2384c71dd 100644 --- a/sdcard/FREQMAN/SSTV.TXT +++ b/sdcard/FREQMAN/SSTV.TXT @@ -1,5 +1,5 @@ # Common SSTV frequencies -# frequencies marked Active have more frequent transmissions. +# frequencies marked Active have more frequent transmissions f=3640000,d=SSTV 80M f=7043000,d=SSTV 40M - Active f=7170000,d=SSTV 40M - Active diff --git a/sdcard/LOOKINGGLASS/PRESETS.TXT b/sdcard/LOOKINGGLASS/PRESETS.TXT index 8114eb7a2..a29bf6eb5 100644 --- a/sdcard/LOOKINGGLASS/PRESETS.TXT +++ b/sdcard/LOOKINGGLASS/PRESETS.TXT @@ -16,11 +16,14 @@ 76,95,FM BROADCAST JAPAN 65,74,FM BROADCAST RUSSIA # CITIZENS BAND RADIO -26,28,CITIZENS BAND RADIO +26,28,CB RADIO # COMMON PUBLIC SERVICE BANDS 150,160, PUBLIC SERVICE 155 450,470,PUBLIC SERVICE 460 769,775,PUBLIC SERVICE 770 +# CubeSats +144,146,145 CubeSats +435,438,436 CubeSats # DECT 1879,1931,DECT # FRS/GMRS From a602abf1d8413d23602abe8d1e94f41cc6d6d2a6 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:04:39 -0500 Subject: [PATCH 95/98] Fix Cancel button in Settings->Autostart (#2087) --- firmware/application/apps/ui_settings.cpp | 19 +++++++++---------- firmware/application/apps/ui_settings.hpp | 5 +++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 92daf09f7..e5ba9cde5 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -840,7 +840,8 @@ void SetMenuColorView::focus() { button_save.focus(); } -/* SetAutostartView*/ +/* SetAutoStartView ************************************/ + SetAutostartView::SetAutostartView(NavigationView& nav) { add_children({&labels, &button_save, @@ -848,7 +849,12 @@ SetAutostartView::SetAutostartView(NavigationView& nav) { &options}); button_save.on_select = [&nav, this](Button&) { - nav_setting.save(); + autostart_app = ""; + if (selected != 0) { + auto it = full_app_list.find(selected); + if (it != full_app_list.end()) + autostart_app = it->second; + } nav.pop(); }; @@ -879,14 +885,7 @@ SetAutostartView::SetAutostartView(NavigationView& nav) { options.set_options(opts); options.on_change = [this](size_t, OptionsField::value_t v) { - if (v == 0) { - autostart_app = ""; - return; - } - auto it = full_app_list.find(v); - if (it != full_app_list.end()) { - autostart_app = it->second; - } + selected = v; }; options.set_selected_index(selected); } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 6e66ebf70..de7929a16 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -817,14 +817,15 @@ class SetAutostartView : public View { "nav"sv, {{"autostart_app"sv, &autostart_app}}}; Labels labels{ - {{1 * 8, 1 * 16}, "Select app to start on boot", Color::light_grey()}}; + {{1 * 8, 1 * 16}, "Select app to start on boot", Color::light_grey()}, + {{2 * 8, 2 * 16}, "(an SD Card is required)", Color::light_grey()}}; Button button_save{ {2 * 8, 16 * 16, 12 * 8, 32}, "Save"}; OptionsField options{ - {0 * 8, 3 * 16}, + {8 * 8, 4 * 16}, 30, {}}; From f091db3270997c4bcaf06a67dfbddd1d8ea2e6c3 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:29:18 +0200 Subject: [PATCH 96/98] Mic audio ak4951 fix + SSTV description (#2088) * fixed too long description, thanks to ImDroided * fixed ak4951 RxAudio not working on startup when enabled --------- Co-authored-by: gullradriel --- firmware/application/apps/ui_mictx.cpp | 30 +++++++++++++------------- sdcard/FREQMAN/SSTV.TXT | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 005303dc4..34066266e 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -523,21 +523,6 @@ MicTXView::MicTXView( }; check_mic_to_HP.set_value(mic_to_HP_enabled); - check_rxactive.on_select = [this](Checkbox&, bool v) { - // vumeter.set_value(0); //Start with a clean vumeter - rx_enabled = v; - check_mic_to_HP.hidden(rx_enabled); // Toggle Hide / show "Hear Mic" checkbox depending if we activate or not the receiver. (if RX on => no visible "Mic Hear" option) - if ((rx_enabled) && (transmitting)) - check_mic_to_HP.set_value(transmitting); // Once we activate the "Rx audio" in reception time we disable "Hear Mic", but we allow it again in TX time. - - if (rx_enabled) - check_va.set_value(false); // Disallow voice activation during RX audio (for now) - Future TODO: Should allow VOX during RX audio - - rxaudio(v); // Activate-Deactivate audio RX (receiver) accordingly - set_dirty(); // Refresh interface - }; - check_rxactive.set_value(rx_enabled); - tx_button.on_select = [this](Button&) { if (!transmitting) { set_tx(true); @@ -590,6 +575,21 @@ MicTXView::MicTXView( // Trigger receiver to update modulation. if (rx_enabled) receiver_model.set_squelch_level(receiver_model.squelch_level()); + + check_rxactive.on_select = [this](Checkbox&, bool v) { + // vumeter.set_value(0); //Start with a clean vumeter + rx_enabled = v; + check_mic_to_HP.hidden(rx_enabled); // Toggle Hide / show "Hear Mic" checkbox depending if we activate or not the receiver. (if RX on => no visible "Mic Hear" option) + if ((rx_enabled) && (transmitting)) + check_mic_to_HP.set_value(transmitting); // Once we activate the "Rx audio" in reception time we disable "Hear Mic", but we allow it again in TX time. + + if (rx_enabled) + check_va.set_value(false); // Disallow voice activation during RX audio (for now) - Future TODO: Should allow VOX during RX audio + + rxaudio(v); // Activate-Deactivate audio RX (receiver) accordingly + set_dirty(); // Refresh interface + }; + check_rxactive.set_value(rx_enabled); } MicTXView::MicTXView( diff --git a/sdcard/FREQMAN/SSTV.TXT b/sdcard/FREQMAN/SSTV.TXT index 2384c71dd..7e5cd77c0 100644 --- a/sdcard/FREQMAN/SSTV.TXT +++ b/sdcard/FREQMAN/SSTV.TXT @@ -1,5 +1,5 @@ # Common SSTV frequencies -# frequencies marked Active have more frequent transmissions +# 'Active' => most used f=3640000,d=SSTV 80M f=7043000,d=SSTV 40M - Active f=7170000,d=SSTV 40M - Active From bfe67a13b739de165db9ee86091c8c9b2cb72dd7 Mon Sep 17 00:00:00 2001 From: gullradriel <3157857+gullradriel@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:59:40 +0200 Subject: [PATCH 97/98] removed dead link (#2089) Co-authored-by: gullradriel --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a7fe06031..50d39cc3e 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,6 @@ This repository expands upon the previous work by many people and aims to consta :heavy_check_mark: Our friends at OpenSourceSDRLab give away five units every three months in our discord (check the badge on top) of their [PortaPack H2](https://www.aliexpress.com/item/4000247041639.html?gatewayAdapt=4itemAdapt), you can support them too by ordering. -:heavy_check_mark: Another popular option is the clone of the [PortaPack H1](https://s.click.aliexpress.com/e/_Dkbqs2X). - :warning: Be cautious , *ask* the seller about compatibility with the latest releases. Look out for the description of the item, if they provide the firmware files for an older version or they have custom setup instructions, this means it might be **NOT compatible**, for example: ![image](https://user-images.githubusercontent.com/1091420/214579017-9ad970b9-0917-48f6-a550-588226d3f89b.png) From 8e90c65a62f4be8b6100b8ee4c9139f091a79ed0 Mon Sep 17 00:00:00 2001 From: jLynx Date: Sun, 7 Apr 2024 16:24:01 +1200 Subject: [PATCH 98/98] v2.0.1 (#2090) * Update version.txt * Update past_version.txt --- .github/workflows/past_version.txt | 2 +- .github/workflows/version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/past_version.txt b/.github/workflows/past_version.txt index ba1e8bf0b..46b105a30 100644 --- a/.github/workflows/past_version.txt +++ b/.github/workflows/past_version.txt @@ -1 +1 @@ -v1.9.1 +v2.0.0 diff --git a/.github/workflows/version.txt b/.github/workflows/version.txt index 46b105a30..0ac852dde 100644 --- a/.github/workflows/version.txt +++ b/.github/workflows/version.txt @@ -1 +1 @@ -v2.0.0 +v2.0.1