Compare commits

...

19 Commits

Author SHA1 Message Date
Gaurav Chaturvedi b66d8b1aa1 Removing vim swap files (#2503)
* Removing vim swap files
* Added vim swap file to .gitignore
2025-01-28 16:31:11 +01:00
gullradriel 8dc3851b55 externalize wipe sdcard (#2502) 2025-01-27 22:10:33 +01:00
gullradriel aef7c2be93 fix baseband (#2501) 2025-01-26 22:23:29 +01:00
gullradriel 4e38dc4d3e put back app in 'Utilities' (#2500)
Co-authored-by: gullradriel <gullradriel@no-mail.com>
2025-01-26 22:15:02 +01:00
Davide Rovelli 520ad97f78 Added different modulations in signal generator (#2492)
* Added DSB, AM 100% mod index and AM 50% mod index. Changed UI.
2025-01-26 21:41:11 +01:00
Lucas C. Villa Real 5bd208bca1 APRS: add frequency settings for Brazil (#2494)
* Add frequency settings for Brazil, named 'BR' that tunes to 145.570 MHz.
* Also added: Japan: 144.640 MHz (JAP), Thailand: 144.900 MHz (THA), Philippines: 144.740 MHz (PHI)
* Reordered list by increasing frequency
Co-authored-by: gullradriel <3157857+gullradriel@users.noreply.github.com>
2025-01-26 21:39:38 +01:00
gullradriel a65ef3ce2e Externalize antenna calc and wav view (#2498)
* externalize antenna calc and wav view
* Added a tool to check if all the pictures in graphics are used in internal apps
2025-01-26 21:36:21 +01:00
gullradriel b2bb37af74 Flipper tx: use file_path, example file (#2496)
* added subghz_dir
* use subghz_dir from file_path
* example file
2025-01-26 17:46:43 +00:00
gullradriel 54ad82a423 fix fallthrough warning (#2497) 2025-01-26 16:27:29 +01:00
gullradriel e463405c77 fix cmake_minimum_required to 3.16 (#2499) 2025-01-26 16:26:02 +01:00
sommermorgentraum c413f925a9 Add fast flash script for sdcard switch hardware (#2480) 2025-01-20 12:43:57 +01:00
Erwin Ried 9e1eb31150 Update README.md
Discord badge was broken, switching to shields.io
2025-01-20 09:22:40 +01:00
sommermorgentraum 7eb08f34cb Fix encoder setting p.mem issue (#2475) 2025-01-09 15:56:14 +01:00
Erwin Ried 2de1f8e6bf Update README.md
Lab401 link with our redirection
2025-01-09 10:05:27 +01:00
sommermorgentraum 55db0e8c87 Add the feature to decide rotate direction of encoder (#2472) 2025-01-08 21:02:05 +01:00
gullradriel dfa35b4290 added discord server information (#2471) 2025-01-07 14:56:08 +01:00
gullradriel 0124051c4f fix for empty text prompt crash (#2468) 2025-01-07 13:46:51 +01:00
gullradriel 65f301399f disabling button on main menu, change labels and add 'icons' (#2466)
* disabling button on main menu, change labels and add 'icons'

* fix reverse order of buttons

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
2025-01-04 10:50:53 +08:00
sommermorgentraum 97889494cf rename bitmaps into bmp 2025-01-03 14:33:30 +01:00
46 changed files with 843 additions and 263 deletions
+1
View File
@@ -61,6 +61,7 @@ cmake-build-debug/
*.sublime-workspace
.vscode
.idea
*.swp
# VSCodium extensions
.history
+1 -1
View File
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301, USA.
#
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.16)
cmake_policy(SET CMP0005 NEW)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex-m.cmake)
+2 -2
View File
@@ -5,7 +5,7 @@
> The only legitimate link to our repositories is the [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware) organization on GitHub.--->
# PortaPack Mayhem
[![Nightly Release](https://github.com/portapack-mayhem/mayhem-firmware/actions/workflows/create_nightly_release.yml/badge.svg?branch=next)](https://github.com/portapack-mayhem/mayhem-firmware/actions/workflows/create_nightly_release.yml) [![CodeScene Code Health](https://codescene.io/projects/8381/status-badges/code-health)](https://codescene.io/projects/8381) [![GitHub All Releases](https://img.shields.io/github/downloads/portapack-mayhem/mayhem-firmware/total)](https://github.com/portapack-mayhem/mayhem-firmware/releases) [![GitHub Releases](https://img.shields.io/github/downloads/portapack-mayhem/mayhem-firmware/latest/total)](https://github.com/portapack-mayhem/mayhem-firmware/releases/latest) [![Docker Hub Pulls](https://img.shields.io/docker/pulls/eried/portapack.svg)](https://hub.docker.com/r/eried/portapack) [![Discord Chat](https://dcbadge.vercel.app/api/server/tuwVMv3?style=flat)](https://discord.gg/tuwVMv3)
[![Nightly Release](https://github.com/portapack-mayhem/mayhem-firmware/actions/workflows/create_nightly_release.yml/badge.svg?branch=next)](https://github.com/portapack-mayhem/mayhem-firmware/actions/workflows/create_nightly_release.yml) [![CodeScene Code Health](https://codescene.io/projects/8381/status-badges/code-health)](https://codescene.io/projects/8381) [![GitHub All Releases](https://img.shields.io/github/downloads/portapack-mayhem/mayhem-firmware/total)](https://github.com/portapack-mayhem/mayhem-firmware/releases) [![GitHub Releases](https://img.shields.io/github/downloads/portapack-mayhem/mayhem-firmware/latest/total)](https://github.com/portapack-mayhem/mayhem-firmware/releases/latest) [![Docker Hub Pulls](https://img.shields.io/docker/pulls/eried/portapack.svg)](https://hub.docker.com/r/eried/portapack) [![Discord Chat](https://img.shields.io/discord/719669764804444213?label=Discord)](https://discord.gg/tuwVMv3)
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). A fork is a derivate, in this case one that has extra features and fixes when compared to the older versions.
@@ -26,7 +26,7 @@ This repository expands upon the previous work by many people and aims to consta
## What to buy?
<!---not direct to h4m but to opensourcesdrlab https://share.hackrf.app/TUOLYI--->
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous H4M [complete](https://share.hackrf.app/HR60Q4) or [upgrade](https://share.hackrf.app/FPLM1H), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://share.hackrf.app/99SAMT). Join their giveaways on discord (check the badge on top). _EU customers_ can purchase via [Lab401](https://lab401.com/products/portapack-h4m).
:heavy_check_mark: ![Static Badge](https://img.shields.io/badge/NEW-yellow) The fabulous H4M [complete](https://share.hackrf.app/HR60Q4) or [upgrade](https://share.hackrf.app/FPLM1H), featuring numerous improvements and accessories. Sold by our friends at [OpenSourceSDRLab](https://share.hackrf.app/99SAMT). Join their giveaways on discord (check the badge on top). _EU customers_ can purchase via [Lab401](https://share.hackrf.app/0CI2CR).
:heavy_check_mark: A recommended one is this [PortaPack H2](https://www.ebay.com/itm/116382397447), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/3d-printed-enclosure).
+1 -1
View File
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301, USA.
#
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.16)
project(firmware)
+1 -4
View File
@@ -305,7 +305,6 @@ set(CPPSRC
apps/ui_recon.cpp
apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp
apps/ui_sd_wipe.cpp
apps/ui_search.cpp
apps/ui_settings.cpp
apps/ui_siggen.cpp
@@ -317,9 +316,7 @@ set(CPPSRC
apps/ui_text_editor.cpp
apps/ui_touch_calibration.cpp
apps/ui_touchtunes.cpp
apps/ui_view_wav.cpp
apps/ui_weatherstation.cpp
apps/ui_whipcalc.cpp
protocols/aprs.cpp
protocols/ax25.cpp
protocols/bht.cpp
@@ -377,7 +374,7 @@ set(INCDIR ${CMAKE_CURRENT_BINARY_DIR} ${COMMON} ${PORTINC} ${KERNINC} ${TESTINC
hw
apps
protocols
bitmaps
bmps
)
#
+43 -16
View File
@@ -39,6 +39,14 @@ using namespace portapack;
using namespace modems;
namespace fs = std::filesystem;
#define BLE_RX_NO_ERROR 0
#define BLE_RX_LIST_FILENAME_EMPTY_ERROR 1
#define BLE_RX_ENTRY_FILENAME_EMPTY_ERROR 2
#define BLE_RX_LIST_SAVE_ERROR 3
#define BLE_RX_ENTRY_SAVE_ERROR 4
static uint8_t ble_rx_error = BLE_RX_NO_ERROR;
void BLELogger::log_raw_data(const std::string& data) {
log_file.write_entry(data);
}
@@ -202,19 +210,23 @@ BleRecentEntryDetailView::BleRecentEntryDetailView(NavigationView& nav, const Bl
}
void BleRecentEntryDetailView::on_save_file(const std::string value, BLETxPacket packetToSave) {
ensure_directory(packet_save_path);
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
auto new_path = folder / value + ext;
saveFile(new_path, packetToSave);
if (value.length() > 0) {
ensure_directory(packet_save_path);
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
auto new_path = folder / value + ext;
ble_rx_error = saveFile(new_path, packetToSave);
} else {
nav_.pop();
ble_rx_error = BLE_RX_ENTRY_FILENAME_EMPTY_ERROR;
}
}
bool BleRecentEntryDetailView::saveFile(const std::filesystem::path& path, BLETxPacket packetToSave) {
File f;
auto error = f.create(path);
if (error)
return false;
return BLE_RX_ENTRY_SAVE_ERROR;
std::string macAddressStr = packetToSave.macAddress;
std::string advertisementDataStr = packetToSave.advertisementData;
@@ -224,7 +236,7 @@ bool BleRecentEntryDetailView::saveFile(const std::filesystem::path& path, BLETx
f.write(packetString.c_str(), packetString.length());
return true;
return BLE_RX_NO_ERROR;
}
void BleRecentEntryDetailView::update_data() {
@@ -568,11 +580,14 @@ std::string BLERxView::build_line_str(BleRecentEntry entry) {
}
void BLERxView::on_save_file(const std::string value) {
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
auto new_path = folder / value + ext;
saveFile(new_path);
if (value.length() > 0) {
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
auto new_path = folder / value + ext;
ble_rx_error = saveFile(new_path);
} else {
ble_rx_error = BLE_RX_LIST_FILENAME_EMPTY_ERROR;
}
}
bool BLERxView::saveFile(const std::filesystem::path& path) {
@@ -584,7 +599,7 @@ bool BLERxView::saveFile(const std::filesystem::path& path) {
auto error = src->open(path, false, true);
if (error) {
return false;
return BLE_RX_LIST_SAVE_ERROR;
}
for (const auto& entry : recent) {
@@ -615,7 +630,7 @@ bool BLERxView::saveFile(const std::filesystem::path& path) {
auto error = dst->open(tempFilePath, false, true);
if (error) {
return false;
return BLE_RX_LIST_SAVE_ERROR;
}
dst->write_line(headerStr.c_str());
@@ -695,7 +710,7 @@ bool BLERxView::saveFile(const std::filesystem::path& path) {
tempList.clear();
return true;
return BLE_RX_NO_ERROR;
}
void BLERxView::on_data(BlePacketData* packet) {
@@ -831,6 +846,18 @@ void BLERxView::on_timer() {
baseband::set_btlerx(randomChannel);
}
}
if (ble_rx_error != BLE_RX_NO_ERROR) {
if (ble_rx_error == BLE_RX_LIST_FILENAME_EMPTY_ERROR) {
nav_.display_modal("Error", "List filename is empty !");
} else if (ble_rx_error == BLE_RX_ENTRY_FILENAME_EMPTY_ERROR) {
nav_.display_modal("Error", "Entry filename is empty !");
} else if (ble_rx_error == BLE_RX_LIST_SAVE_ERROR) {
nav_.display_modal("Error", "Couldn't save list !");
} else if (ble_rx_error == BLE_RX_ENTRY_SAVE_ERROR) {
nav_.display_modal("Error", "Couldn't save entry !");
}
ble_rx_error = BLE_RX_NO_ERROR;
}
}
void BLERxView::handle_entries_sort(uint8_t index) {
+14 -13
View File
@@ -7,30 +7,33 @@
namespace ui {
// Information: a line starting with a '#' will be yellow coloured
constexpr std::string_view authors_list[] = {
"# * List of contributors * ",
constexpr std::string_view mayhem_information_list[] = {
"#****** Mayhem Community ******",
" ",
" https://discord.mayhem.app",
" ",
"#**** List of contributors ****",
" ",
"#Mayhem-Firmware:",
"jboone,eried,furrtek,",
"NotherNgineer,gullradriel,",
"jLynx,kallanreed,Brumi-2021,",
"htotoo,bernd-herzog,zxkmm,",
"htotoo,zxkmm,bernd-herzog,",
"ArjanOnwezen,euquiq,u-foka,",
"iNetro,heurist1,dqs105,",
"teixeluis,jwetzell,",
"jimilinuxguy,gregoryfenton,",
"notpike,strijar,BehleZebub,",
"arneluehrs,rascafr,joyel24,",
"ImDroided,zigad,johnelder,",
"klockee,nnesetto,LupusE,",
"argilo,dc2dc,formtapez,",
"arneluehrs,mcules,rascafr,",
"joyel24,ImDroided,zigad,",
"johnelder,klockee,nnesetto,",
"LupusE,argilo,dc2dc,formtapez,",
"RocketGod-git,mrmookie,",
"ITAxReal,F33RNI,F4GEV,",
"rusty-labs,mjwaxios,andrej-mk,",
"RedFox-Fr,nemanjan00,",
"MichalLeonBorsuk,",
"MatiasFernandez,Giorgiofox,",
"ckuethe",
"MatiasFernandez,Giorgiofox",
" ",
"#Havoc:",
"jboone,furrtek,eried,argilo,",
@@ -72,7 +75,7 @@ AboutView::AboutView(NavigationView& nav) {
button_ok.focus();
};
for (auto& authors_line : authors_list) {
for (auto& authors_line : mayhem_information_list) {
// if it's starting with #, it's a title and we have to substract the '#' and paint yellow
if (authors_line.size() > 0) {
if (authors_line[0] == '#') {
@@ -103,15 +106,13 @@ void AboutView::on_frame_sync() {
menu_view.set_highlighted(current + 1);
} else {
menu_view.set_highlighted(0);
// ^ to go back to the REAL top instead of make the 2 at the top to make the title disappeares
menu_view.set_highlighted(2); // the first line that has human name
}
}
}
void AboutView::focus() {
button_ok.focus();
menu_view.set_highlighted(2); // the first line that has human name
menu_view.set_highlighted(3); // contributors block starting line
}
bool AboutView::on_touch(const TouchEvent) {
+14 -6
View File
@@ -99,13 +99,21 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect)
field_frequency.set_value(aprs_rx_freq);
} else if (i == 1) { // NA - North America - is also the default
field_frequency.set_value(144390000);
} else if (i == 2) { // EUR
field_frequency.set_value(144800000);
} else if (i == 3) { // AUS
field_frequency.set_value(145175000);
} else if (i == 4) { // NZ
} else if (i == 2) { // NZ
field_frequency.set_value(144575000);
} else if (i == 5) { // ISS
} else if (i == 3) { // JAP
field_frequency.set_value(144640000);
} else if (i == 4) { // PHI
field_frequency.set_value(144740000);
} else if (i == 5) { // EUR
field_frequency.set_value(144800000);
} else if (i == 6) { // THA
field_frequency.set_value(144900000);
} else if (i == 7) { // AUS
field_frequency.set_value(145175000);
} else if (i == 8) { // BR
field_frequency.set_value(145570000);
} else if (i == 9) { // ISS
field_frequency.set_value(145825000);
}
options_region_id = i;
+8 -4
View File
@@ -227,10 +227,14 @@ class APRSRxView : public View {
3,
{{"MAN", 0},
{"NA ", 1},
{"EUR", 2},
{"AUS", 3},
{"NZ ", 4},
{"ISS", 5}}};
{"NZ ", 2},
{"JAP", 3},
{"PHI", 4},
{"EUR", 5},
{"THA", 6},
{"AUS", 7},
{"BR ", 8},
{"ISS", 9}}};
FrequencyField field_frequency{
{3 * 8, 0 * 16}};
@@ -177,4 +177,4 @@ void FlashUtilityView::focus() {
menu_view.focus();
}
} /* namespace ui */
} /* namespace ui */
+4 -1
View File
@@ -711,10 +711,12 @@ SetEncoderDialView::SetEncoderDialView(NavigationView& nav) {
&button_dial_sensitivity_plus,
&button_dial_sensitivity_minus,
&button_rate_multiplier_plus,
&button_rate_multiplier_minus});
&button_rate_multiplier_minus,
&field_encoder_dial_direction});
field_encoder_dial_sensitivity.set_by_value(pmem::encoder_dial_sensitivity());
field_encoder_rate_multiplier.set_value(pmem::encoder_rate_multiplier());
field_encoder_dial_direction.set_by_value(pmem::encoder_dial_direction());
button_dial_sensitivity_plus.on_select = [this](Button&) {
field_encoder_dial_sensitivity.on_encoder(1);
@@ -732,6 +734,7 @@ SetEncoderDialView::SetEncoderDialView(NavigationView& nav) {
button_save.on_select = [&nav, this](Button&) {
pmem::set_encoder_dial_sensitivity(field_encoder_dial_sensitivity.selected_index_value());
pmem::set_encoder_rate_multiplier(field_encoder_rate_multiplier.value());
pmem::set_encoder_dial_direction(field_encoder_dial_direction.selected_index_value());
nav.pop();
};
+21 -14
View File
@@ -574,6 +574,7 @@ class SetQRCodeView : public View {
};
};
using portapack::persistent_memory::encoder_dial_direction;
using portapack::persistent_memory::encoder_dial_sensitivity;
using portapack::persistent_memory::encoder_rate_multiplier;
@@ -587,44 +588,50 @@ class SetEncoderDialView : public View {
private:
Labels labels{
{{1 * 8, 1 * 16}, "Adjusts sensitivity to dial", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 2 * 16}, "rotation position (number of", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 3 * 16}, "steps per full rotation):", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 5 * 16}, "Dial sensitivity:", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 8 * 16}, "Adjusts sensitivity to dial", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 9 * 16}, "rotation rate (default 1", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 10 * 16}, "means no rate dependency):", Theme::getInstance()->fg_light->foreground},
{{3 * 8, 12 * 16}, "Rate multiplier:", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 0 * 16}, "Sensitivity to dial rotation", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 1 * 16}, "position (x steps per 360):", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 3 * 16}, "Sensitivity:", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 7 * 16}, "Rotation rate (default 1", Theme::getInstance()->fg_light->foreground},
{{0 * 8, 8 * 16}, "means no rate dependency):", Theme::getInstance()->fg_light->foreground},
{{2 * 8, 10 * 16}, "Rate multiplier:", Theme::getInstance()->fg_light->foreground},
{{4 * 8, 14 * 16}, "Direction:", Theme::getInstance()->fg_light->foreground},
};
OptionsField field_encoder_dial_sensitivity{
{20 * 8, 5 * 16},
{20 * 8, 3 * 16},
6,
{{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW},
{"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL},
{"HIGH", encoder_dial_sensitivity::DIAL_SENSITIVITY_HIGH}}};
NumberField field_encoder_rate_multiplier{
{20 * 8, 12 * 16},
{20 * 8, 10 * 16},
2,
{1, 15},
1,
' '};
OptionsField field_encoder_dial_direction{
{18 * 8, 14 * 16},
7,
{{"NORMAL", false},
{"REVERSE", true}}};
Button button_dial_sensitivity_plus{
{20 * 8, 4 * 16, 16, 16},
{20 * 8, 2 * 16, 16, 16},
"+"};
Button button_dial_sensitivity_minus{
{20 * 8, 6 * 16, 16, 16},
{20 * 8, 4 * 16, 16, 16},
"-"};
Button button_rate_multiplier_plus{
{20 * 8, 11 * 16, 16, 16},
{20 * 8, 9 * 16, 16, 16},
"+"};
Button button_rate_multiplier_minus{
{20 * 8, 13 * 16, 16, 16},
{20 * 8, 11 * 16, 16, 16},
"-"};
Button button_save{
+33 -6
View File
@@ -44,9 +44,9 @@ SigGenView::~SigGenView() {
void SigGenView::update_config() {
if (checkbox_stop.value())
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), field_stop.value());
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), (options_mod.selected_index_value() << 4) + options_shape.selected_index_value(), field_stop.value());
else
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), options_shape.selected_index_value(), 0);
baseband::set_siggen_config(transmitter_model.channel_bandwidth(), (options_mod.selected_index_value() << 4) + options_shape.selected_index_value(), 0);
}
void SigGenView::update_tone() {
@@ -78,6 +78,7 @@ SigGenView::SigGenView(
baseband::run_image(portapack::spi_flash::image_tag_siggen);
add_children({&labels,
&options_mod,
&options_shape,
&text_shape,
&symfield_tone,
@@ -87,22 +88,48 @@ SigGenView::SigGenView(
&field_stop,
&tx_view});
symfield_tone.hidden(1); // At first launch , by default we are in CW Shape has NO MOD , we are not using Tone modulation.
symfield_tone.hidden(true); // At first launch , by default we are in CW: Shape ignored, we are not using Tone modulation.
options_shape.hidden(true);
text_shape.hidden(true);
symfield_tone.set_value(1000); // Default: 1000 Hz
options_shape.on_change = [this](size_t, OptionsField::value_t v) {
text_shape.set(shape_strings[v]);
if (auto_update)
update_config();
if ((v == 0) || (v == 6)) { // In Shapes Options (CW & Pseudo Random Noise) we are not using Tone modulation freq.
symfield_tone.hidden(1);
if (v == 5) { // In Shape Pseudo Random Noise we are not using Tone modulation freq.
symfield_tone.hidden(true);
} else {
symfield_tone.hidden(0);
symfield_tone.hidden(false);
}
set_dirty();
};
options_shape.set_selected_index(0);
text_shape.set(shape_strings[0]);
options_mod.on_change = [this](size_t, OptionsField::value_t v) {
if (auto_update)
update_config();
if (v == 0) { // In Modulation Options CW we are not using Tone modulation freq.
symfield_tone.hidden(true);
} else {
symfield_tone.hidden(false);
}
if ((v == 0) || (v == 2) || (v == 3)) { // In Modulation Options CW, QPSK, BPSK we are not using Shapes.
options_shape.hidden(true);
text_shape.hidden(true);
} else {
options_shape.hidden(false);
text_shape.hidden(false);
}
set_dirty();
};
options_mod.set_selected_index(0);
field_stop.set_value(1);
symfield_tone.set_value(1000); // Default: 1000 Hz
+35 -30
View File
@@ -58,68 +58,73 @@ class SigGenView : public View {
app_settings::SettingsManager settings_{
"tx_siggen", app_settings::Mode::TX};
const std::string shape_strings[9] = {
"CW (No mod.) ",
"Sine mod. FM",
"Triangle mod.FM", // max 15 character text space.
"Saw up mod. FM",
"Saw down mod.FM",
"Square mod. FM",
"Pseudo Noise FM", // using 16 bits LFSR register, 16 order polynomial feedback.
"BPSK 0,1,0,1...",
"QPSK 00-01-10.."};
const std::string shape_strings[6] = {// max 15 character text space.
"Sine",
"Triangle",
"Saw up",
"Saw down",
"Square",
"Pseudo Noise"};
bool auto_update{false};
Labels labels{
{{3 * 8, 4 + 10}, "Shape:", Theme::getInstance()->fg_light->foreground},
{{6 * 8, 7 * 8}, "Tone: Hz", Theme::getInstance()->fg_light->foreground},
{{22 * 8, 15 * 8 + 4}, "s.", Theme::getInstance()->fg_light->foreground},
{{8 * 8, 20 * 8}, "Modulation: FM", Theme::getInstance()->fg_light->foreground}};
{{3 * 8, 2 * 8}, "Modulation:", Theme::getInstance()->fg_light->foreground},
{{3 * 8, 3 * 8 + 8 + 10}, "Shape:", Theme::getInstance()->fg_light->foreground},
{{6 * 8, 2 * 8 + 7 * 8}, "Tone: Hz", Theme::getInstance()->fg_light->foreground},
{{22 * 8, 2 * 8 + 15 * 8 + 4}, "s.", Theme::getInstance()->fg_light->foreground}};
ImageOptionsField options_shape{
{10 * 8, 4, 32, 32},
{10 * 8, 3 * 8 + 8, 32, 32},
Theme::getInstance()->bg_darkest->foreground,
Theme::getInstance()->bg_darkest->background,
{{&bitmap_sig_cw, 0},
{&bitmap_sig_sine, 1},
{&bitmap_sig_tri, 2},
{&bitmap_sig_saw_up, 3},
{&bitmap_sig_saw_down, 4},
{&bitmap_sig_square, 5},
{&bitmap_sig_noise, 6},
{&bitmap_sig_noise, 7}, // Pending to add a correct BPSK icon.
{&bitmap_sig_noise, 8}}}; // Pending to add a correct QPSK icon.
{{&bitmap_sig_sine, 0},
{&bitmap_sig_tri, 1},
{&bitmap_sig_saw_up, 2},
{&bitmap_sig_saw_down, 3},
{&bitmap_sig_square, 4},
{&bitmap_sig_noise, 5}}};
Text text_shape{
{15 * 8, 4 + 10, 15 * 8, 16},
{15 * 8, 3 * 8 + 8 + 10, 15 * 8, 16},
""};
SymField symfield_tone{
{12 * 8, 7 * 8},
{12 * 8, 2 * 8 + 7 * 8},
5};
Button button_update{
{5 * 8, 10 * 8, 8 * 8, 3 * 8},
{5 * 8, 2 * 8 + 10 * 8, 8 * 8, 3 * 8},
"Update"};
Checkbox checkbox_auto{
{15 * 8, 10 * 8},
{15 * 8, 2 * 8 + 10 * 8},
4,
"Auto"};
Checkbox checkbox_stop{
{5 * 8, 15 * 8},
{5 * 8, 2 * 8 + 15 * 8},
10,
"Stop after"};
NumberField field_stop{
{20 * 8, 15 * 8 + 4},
{20 * 8, 2 * 8 + 15 * 8 + 4},
2,
{1, 99},
1,
' '};
OptionsField options_mod{
{15 * 8, 2 * 8},
12,
{{"CW (No mod.)", 0},
{"FM", 1},
{"BPSK", 2},
{"QPSK", 3},
{"DSB", 4},
{"AM 100% dep.", 5},
{"AM 50% depth", 6}}};
TransmitterView tx_view{
16 * 16,
10000,
+39 -76
View File
@@ -987,44 +987,6 @@ static constexpr Bitmap bitmap_icon_previous{
{16, 16},
bitmap_icon_previous_data};
static constexpr uint8_t bitmap_icon_tools_antenna_data[] = {
0x38,
0x3E,
0x10,
0x22,
0x10,
0x26,
0x10,
0x22,
0x10,
0x2E,
0x10,
0x22,
0x10,
0x26,
0x10,
0x22,
0x38,
0x2E,
0x38,
0x22,
0x38,
0x26,
0x38,
0x22,
0x38,
0x2E,
0x38,
0x22,
0x38,
0x3E,
0x00,
0x00,
};
static constexpr Bitmap bitmap_icon_tools_antenna{
{16, 16},
bitmap_icon_tools_antenna_data};
static constexpr uint8_t bitmap_icon_batt_text_data[] = {
0x00,
0x00,
@@ -1799,6 +1761,45 @@ static constexpr uint8_t bitmap_icon_lge_data[] = {
0x00,
0x00,
};
static constexpr uint8_t bitmap_icon_file_iq_data[] = {
0xFC,
0x03,
0x04,
0x06,
0x04,
0x0E,
0x04,
0x1E,
0x04,
0x3E,
0x04,
0x20,
0x04,
0x20,
0x04,
0x21,
0x44,
0x25,
0x54,
0x25,
0xF4,
0x2F,
0xA4,
0x2A,
0x84,
0x22,
0x04,
0x22,
0x04,
0x20,
0xFC,
0x3F,
};
static constexpr Bitmap bitmap_icon_file_iq{
{16, 16},
bitmap_icon_file_iq_data};
static constexpr Bitmap bitmap_icon_lge{
{16, 16},
bitmap_icon_lge_data};
@@ -2713,44 +2714,6 @@ static constexpr Bitmap bitmap_icon_touchtunes{
{16, 16},
bitmap_icon_touchtunes_data};
static constexpr uint8_t bitmap_icon_file_iq_data[] = {
0xFC,
0x03,
0x04,
0x06,
0x04,
0x0E,
0x04,
0x1E,
0x04,
0x3E,
0x04,
0x20,
0x04,
0x20,
0x04,
0x21,
0x44,
0x25,
0x54,
0x25,
0xF4,
0x2F,
0xA4,
0x2A,
0x84,
0x22,
0x04,
0x22,
0x04,
0x20,
0xFC,
0x3F,
};
static constexpr Bitmap bitmap_icon_file_iq{
{16, 16},
bitmap_icon_file_iq_data};
static constexpr uint8_t bitmap_icon_sd_data[] = {
0x00,
0x00,
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2024 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_whipcalc.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::antenna_length {
void initialize_app(ui::NavigationView& nav) {
nav.push<WhipCalcView>();
}
} // namespace ui::external_app::antenna_length
extern "C" {
__attribute__((section(".external_app.app_antenna_length.application_information"), used)) application_information_t _application_information_antenna_length = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::antenna_length::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Antenna Length",
/*.bitmap_data = */ {0x38, 0x3E, 0x10, 0x22, 0x10, 0x26, 0x10, 0x22, 0x10, 0x2E, 0x10, 0x22, 0x10, 0x26, 0x10, 0x22, 0x38, 0x2E, 0x38, 0x22, 0x38, 0x26, 0x38, 0x22, 0x38, 0x2E, 0x38, 0x22, 0x38, 0x3E, 0x00, 0x00},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -32,8 +32,9 @@
#include <cstring>
using namespace portapack;
using namespace ui;
namespace ui {
namespace ui::external_app::antenna_length {
void WhipCalcView::focus() {
field_frequency.focus();
@@ -176,4 +177,4 @@ void WhipCalcView::load_antenna_db() {
void WhipCalcView::add_default_antenna() {
antenna_db.push_back({"ANT500", {185, 315, 450, 586, 724, 862}}); // store a default ant500
}
} // namespace ui
} // namespace ui::external_app::antenna_length
@@ -31,7 +31,10 @@
#include "string_format.hpp"
#include <vector>
namespace ui {
using namespace ui;
namespace ui::external_app::antenna_length {
class WhipCalcView : public View {
public:
WhipCalcView(NavigationView& nav);
@@ -90,6 +93,6 @@ class WhipCalcView : public View {
"Back"};
};
} /* namespace ui */
} // namespace ui::external_app::antenna_length
#endif /*__UI_WHIPCALC__*/
+16 -1
View File
@@ -150,6 +150,18 @@ set(EXTCPPSRC
#app_manager
external/app_manager/main.cpp
external/app_manager/ui_app_manager.cpp
# whip calculator
external/antenna_length/main.cpp
external/antenna_length/ui_whipcalc.cpp
# wav viewer
external/wav_view/main.cpp
external/wav_view/ui_view_wav.cpp
# wipe sdcard
external/sd_wipe/main.cpp
external/sd_wipe/ui_sd_wipe.cpp
)
set(EXTAPPLIST
@@ -189,4 +201,7 @@ set(EXTAPPLIST
tuner
metronome
app_manager
)
antenna_length
view_wav
sd_wipe
)
+21
View File
@@ -59,6 +59,9 @@ MEMORY
ram_external_app_tuner(rwx) : org = 0xADD20000, len = 32k
ram_external_app_metronome(rwx) : org = 0xADD30000, len = 32k
ram_external_app_app_manager(rwx) : org = 0xADD40000, len = 32k
ram_external_app_antenna_length(rwx) : org = 0xADD50000, len = 32k
ram_external_app_view_wav(rwx) : org = 0xADD60000, len = 32k
ram_external_app_sd_wipe(rwx) : org = 0xADD70000, len = 32k
}
SECTIONS
@@ -279,4 +282,22 @@ SECTIONS
KEEP(*(.external_app.app_app_manager.application_information));
*(*ui*external_app*app_manager*);
} > ram_external_app_app_manager
.external_app_antenna_length : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_antenna_length.application_information));
*(*ui*external_app*antenna_length*);
} > ram_external_app_antenna_length
.external_app_view_wav : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_view_wav.application_information));
*(*ui*external_app*view_wav*);
} > ram_external_app_view_wav
.external_app_sd_wipe : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_sd_wipe.application_information));
*(*ui*external_app*sd_wipe*);
} > ram_external_app_sd_wipe
}
@@ -89,8 +89,6 @@ class FlipperTxView : public View {
std::unique_ptr<FlipperPlayThread> replay_thread{};
Optional<flippersub_metadata> submeta{};
const std::filesystem::path subghz_dir = u"subghz";
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress,
[this](const Message* const p) {
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2024 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_sd_wipe.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::sd_wipe {
void initialize_app(ui::NavigationView& nav) {
nav.push<WipeSDView>();
}
} // namespace ui::external_app::sd_wipe
extern "C" {
__attribute__((section(".external_app.app_sd_wipe.application_information"), used)) application_information_t _application_information_sd_wipe = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::sd_wipe::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Wipe SD card",
/*.bitmap_data = */ {0xF0, 0x3F, 0x58, 0x35, 0x5C, 0x35, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0x3C, 0x1C, 0xBC, 0xC9, 0xBC, 0xE3, 0x2C, 0x77, 0x5C, 0x3E, 0xAC, 0x1C, 0x5C, 0x3E, 0x2C, 0x77, 0x9C, 0xE3, 0xAC, 0xC1},
/*.icon_color = */ ui::Color::red().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -22,7 +22,9 @@
#include "ui_sd_wipe.hpp"
namespace ui {
using namespace ui;
namespace ui::external_app::sd_wipe {
Thread* WipeSDView::thread{nullptr};
@@ -63,4 +65,4 @@ void WipeSDView::focus() {
}
}
} /* namespace ui */
} // namespace ui::external_app::sd_wipe
@@ -30,7 +30,9 @@
#include <cstdint>
namespace ui {
using namespace ui;
namespace ui::external_app::sd_wipe {
class WipeSDView : public View {
public:
@@ -87,6 +89,6 @@ class WipeSDView : public View {
""};
};
} /* namespace ui */
} // namespace ui::external_app::sd_wipe
#endif /*__UI_SD_WIPE_H__*/
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2024 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_view_wav.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::view_wav {
void initialize_app(ui::NavigationView& nav) {
nav.push<ViewWavView>();
}
} // namespace ui::external_app::view_wav
extern "C" {
__attribute__((section(".external_app.app_view_wav.application_information"), used)) application_information_t _application_information_view_wav = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::view_wav::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "WAV Viewer",
/*.bitmap_data = */ {0xF0, 0x0F, 0x1C, 0x18, 0x17, 0x38, 0x15, 0x78, 0x15, 0xF8, 0x15, 0x82, 0x15, 0x8B, 0xD5, 0x83, 0xD5, 0xBB, 0xD5, 0x83, 0x15, 0x8B, 0x15, 0x92, 0x15, 0xA0, 0x17, 0x80, 0x1C, 0x80, 0xF0, 0xFF},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'T', 'X'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -28,8 +28,9 @@
#include "string_format.hpp"
using namespace portapack;
using namespace ui;
namespace ui {
namespace ui::external_app::view_wav {
void ViewWavView::update_scale(int32_t new_scale) {
scale = new_scale;
@@ -345,4 +346,4 @@ ViewWavView::~ViewWavView() {
baseband::shutdown();
}
} /* namespace ui */
} /* namespace ui::external_app::view_wav */
@@ -28,7 +28,9 @@
#include "ui_receiver.hpp"
#include "replay_thread.hpp"
namespace ui {
using namespace ui;
namespace ui::external_app::view_wav {
class ViewWavView : public View {
public:
@@ -202,4 +204,4 @@ class ViewWavView : public View {
}};
};
} /* namespace ui */
} /* namespace ui::external_app::view_wav */
+1
View File
@@ -49,3 +49,4 @@ const std::filesystem::path sstv_dir = u"SSTV";
const std::filesystem::path wav_dir = u"WAV";
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
const std::filesystem::path ook_editor_dir = u"OOKFILES";
const std::filesystem::path subghz_dir = u"SUBGHZ";
+1
View File
@@ -51,5 +51,6 @@ extern const std::filesystem::path sstv_dir;
extern const std::filesystem::path wav_dir;
extern const std::filesystem::path whipcalc_dir;
extern const std::filesystem::path ook_editor_dir;
extern const std::filesystem::path subghz_dir;
#endif /* __FILE_PATH_H__ */
+5
View File
@@ -66,6 +66,11 @@ int_fast8_t Encoder::update(const uint_fast8_t phase_bits) {
if (direction == prev_direction) {
if ((sensitivity_map[portapack::persistent_memory::encoder_dial_sensitivity()] & (1 << state)) == 0)
return 0;
// false: normal, true: reverse
if (portapack::persistent_memory::encoder_dial_direction())
direction = -direction;
return direction;
}
+8 -4
View File
@@ -110,12 +110,12 @@ void BtnGridView::set_arrow_up_enabled(bool enabled) {
if (enabled) {
if (!arrow_up_enabled) {
arrow_up_enabled = true;
button_pgup.set_text("PAGE UP");
button_pgup.set_text("< PREV");
}
} else if (!enabled) {
if (arrow_up_enabled) {
arrow_up_enabled = false;
button_pgup.set_text(" ");
button_pgup.set_text(" ");
}
}
};
@@ -126,12 +126,12 @@ void BtnGridView::set_arrow_down_enabled(bool enabled) {
if (enabled) {
if (!arrow_down_enabled) {
arrow_down_enabled = true;
button_pgdown.set_text("PAGE DOWN");
button_pgdown.set_text("NEXT >");
}
} else if (!enabled) {
if (arrow_down_enabled) {
arrow_down_enabled = false;
button_pgdown.set_text(" ");
button_pgdown.set_text(" ");
}
}
};
@@ -228,6 +228,10 @@ NewButton* BtnGridView::item_view(size_t index) const {
void BtnGridView::show_arrows_enabled(bool enabled) {
show_arrows = enabled;
if (!enabled) {
remove_child(&button_pgup);
remove_child(&button_pgdown);
}
}
bool BtnGridView::set_highlighted(int32_t new_value) {
+1 -9
View File
@@ -54,7 +54,6 @@
#include "ui_recon.hpp"
#include "ui_scanner.hpp"
#include "ui_sd_over_usb.hpp"
#include "ui_sd_wipe.hpp"
#include "ui_search.hpp"
#include "ui_settings.hpp"
#include "ui_siggen.hpp"
@@ -63,10 +62,8 @@
// #include "ui_test.hpp"
#include "ui_text_editor.hpp"
#include "ui_touchtunes.hpp"
#include "ui_view_wav.hpp"
#include "ui_weatherstation.hpp"
#include "ui_subghzd.hpp"
#include "ui_whipcalc.hpp"
#include "ui_battinfo.hpp"
#include "ui_external_items_menu_loader.hpp"
@@ -153,7 +150,6 @@ const NavigationView::AppList NavigationView::appList = {
//{"sstv", "SSTV", RX, Color::dark_grey(), &bitmap_icon_sstv, new ViewFactory<NotImplementedView>()},
//{"tetra", "TETRA", RX, Color::dark_grey(), &bitmap_icon_tetra, new ViewFactory<NotImplementedView>()},
/* TX ********************************************************************/
//{"adsbtx", "ADS-B TX", TX, ui::Color::green(), &bitmap_icon_adsb, new ViewFactory<ADSBTxView>()},
{"aprstx", "APRS TX", TX, ui::Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSTXView>()},
{"bht", "BHT Xy/EP", TX, ui::Color::green(), &bitmap_icon_bht, new ViewFactory<BHTView>()},
{"bletx", "BLE Tx", TX, ui::Color::green(), &bitmap_icon_btle, new ViewFactory<BLETxView>()},
@@ -163,19 +159,15 @@ const NavigationView::AppList NavigationView::appList = {
{"soundbrd", "Soundbrd", TX, ui::Color::green(), &bitmap_icon_soundboard, new ViewFactory<SoundBoardView>()},
{"touchtune", "TouchTune", TX, ui::Color::green(), &bitmap_icon_touchtunes, new ViewFactory<TouchTunesView>()},
/* UTILITIES *************************************************************/
{"antennalength", "Antenna Length", UTILITIES, Color::green(), &bitmap_icon_tools_antenna, new ViewFactory<WhipCalcView>()},
{"filemanager", "File Manager", UTILITIES, Color::green(), &bitmap_icon_dir, new ViewFactory<FileManagerView>()},
{"freqman", "Freq. Manager", UTILITIES, Color::green(), &bitmap_icon_freqman, new ViewFactory<FrequencyManagerView>()},
{"notepad", "Notepad", UTILITIES, Color::dark_cyan(), &bitmap_icon_notepad, new ViewFactory<TextEditorView>()},
{"iqtrim", "IQ Trim", UTILITIES, Color::orange(), &bitmap_icon_trim, new ViewFactory<IQTrimView>()},
{"notepad", "Notepad", UTILITIES, Color::dark_cyan(), &bitmap_icon_notepad, new ViewFactory<TextEditorView>()},
{nullptr, "SD Over USB", UTILITIES, Color::yellow(), &bitmap_icon_hackrf, new ViewFactory<SdOverUsbView>()},
{"signalgen", "Signal Gen", UTILITIES, Color::green(), &bitmap_icon_cwgen, new ViewFactory<SigGenView>()},
//{"testapp", "Test App", UTILITIES, Color::dark_grey(), nullptr, new ViewFactory<TestView>()},
{"wavview", "Wav View", UTILITIES, Color::yellow(), &bitmap_icon_soundboard, new ViewFactory<ViewWavView>()},
// Dangerous apps.
{nullptr, "Flash Utility", UTILITIES, Color::red(), &bitmap_icon_peripherals_details, new ViewFactory<FlashUtilityView>()},
{nullptr, "Wipe SD card", UTILITIES, Color::red(), &bitmap_icon_tools_wipesd, new ViewFactory<WipeSDView>()},
};
const NavigationView::AppMap NavigationView::appMap = generate_app_map(NavigationView::appList);
+67 -48
View File
@@ -38,28 +38,67 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
} else
sample_count--;
if (tone_shape == 0) {
if (modulation == 0) {
// CW
re = 127; // max. signed 8 bits value . (-128 ...+127), max. amplitude , static phasor at 0º
im = 0;
} else {
if (tone_shape == 1) {
} else if (modulation == 2) {
// Digital BPSK consecutive 0,1,0,...continuous cycle, 1 bit/symbol, at rate of 2 symbols / Freq Tone Periode... without any Pulse shape at the moment .
re = (((tone_phase & 0xFF000000) >> 24) & 0x80) ? 127 : -128; // Sending 2 bits by Periode T of the GUI tone, alternative static phasor to 0, -180º , 0º
im = 0;
tone_phase += tone_delta; // In BPSK-QSPK we are using to calculate each 1/4 of the periode.
} else if (modulation == 3) {
// Digital QPSK consecutive 00, 01, 10, 11,00, ...continuous cycle ,2 bits/symbol, at rate of 4 symbols / Freq Tone Periode. not random., without any Pulse shape at the moment .
switch (((tone_phase & 0xFF000000) >> 24)) {
case 0 ... 63: // equivalent to 1/4 of total 360º degrees.
/* "00" */
re = (sine_table_i8[32]); // we are sending symbol-phasor 45º during 1/4 of the total periode
im = (sine_table_i8[32 + 64]); // 32 index = rounded (45º/360º * 255 total sin table steps) = 31,875
break;
case 64 ... 127:
/* "01" */
re = (sine_table_i8[96]); // symbol-phasor 135º
im = (sine_table_i8[96 + 64]); // 96 index = 32 + 256/4
break;
break;
case 128 ... 191:
/* "10" */
re = (sine_table_i8[159]); // symbol-phasor 225º
im = (sine_table_i8[159 + 64]); // 159 rounded index = 96 + 256/4 = 159.3
break;
case 192 ... 255:
/* "11" */
re = (sine_table_i8[223]); // symbol-phasor 315º ; 223 rounded index = (315/360) * 255 =223.125
im = (sine_table_i8[((223 + 64) & 0xFF)]); // Max index 255, circular periodic conversion.
break;
default:
break;
}
tone_phase += tone_delta; // In BPSK-QSPK we are using to calculate each 1/4 of the periode.
} else { // Other modulations: FM, DSB, AM
if (tone_shape == 0) {
// Sine
sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]);
} else if (tone_shape == 2) {
} else if (tone_shape == 1) {
// Triangle
int8_t a = (tone_phase & 0xFF000000) >> 24;
sample = (a & 0x80) ? ((a << 1) ^ 0xFF) - 0x80 : (a << 1) + 0x80;
} else if (tone_shape == 3) {
} else if (tone_shape == 2) {
// Saw up
sample = ((tone_phase & 0xFF000000) >> 24);
} else if (tone_shape == 4) {
} else if (tone_shape == 3) {
// Saw down
sample = ((tone_phase & 0xFF000000) >> 24) ^ 0xFF;
} else if (tone_shape == 5) {
} else if (tone_shape == 4) {
// Square
sample = (((tone_phase & 0xFF000000) >> 24) & 0x80) ? 127 : -128;
} else if (tone_shape == 6) {
} else if (tone_shape == 5) {
// Noise generator, pseudo random noise generator, 16 bits linear-feedback shift register (LFSR) algorithm, variant Fibonacci.
// https://en.wikipedia.org/wiki/Linear-feedback_shift_register
// 16 bits LFSR .taps: 16, 15, 13, 4 ;feedback polynomial: x^16 + x^15 + x^13 + x^4 + 1
@@ -79,49 +118,13 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
if (counter == 15) {
counter = 0;
}
} else if (tone_shape == 7) {
// Digital BPSK consecutive 0,1,0,...continuous cycle, 1 bit/symbol, at rate of 2 symbols / Freq Tone Periode... without any Pulse shape at the moment .
re = (((tone_phase & 0xFF000000) >> 24) & 0x80) ? 127 : -128; // Sending 2 bits by Periode T of the GUI tone, alternative static phasor to 0, -180º , 0º
im = 0;
} else if (tone_shape == 8) {
// Digital QPSK consecutive 00, 01, 10, 11,00, ...continuous cycle ,2 bits/symbol, at rate of 4 symbols / Freq Tone Periode. not random., without any Pulse shape at the moment .
switch (((tone_phase & 0xFF000000) >> 24)) {
case 0 ... 63: // equivalent to 1/4 of total 360º degrees.
/* "00" */
re = (sine_table_i8[32]); // we are sending symbol-phasor 45º during 1/4 of the total periode
im = (sine_table_i8[32 + 64]); // 32 index = rounded (45º/360º * 255 total sin table steps) = 31,875
break;
case 64 ... 127:
/* "01" */
re = (sine_table_i8[96]); // symbol-phasor 135º
im = (sine_table_i8[96 + 64]); // 96 index = 32 + 256/4
break;
break;
case 128 ... 191:
/* "10" */
re = (sine_table_i8[159]); // symbol-phasor 225º
im = (sine_table_i8[159 + 64]); // 159 rounded index = 96 + 256/4 = 159.3
break;
case 192 ... 255:
/* "11" */
re = (sine_table_i8[223]); // symbol-phasor 315º ; 223 rounded index = (315/360) * 255 =223.125
im = (sine_table_i8[((223 + 64) & 0xFF)]); // Max index 255, circular periodic conversion.
break;
default:
break;
}
}
if (tone_shape != 6) { //(all except Pseudo Random White Noise). We are in (1):periodic signals or (2):BPSK/QPSK , in both cases ,we need Tone updated acum sum phases to modulate in FM / or control phasor phase (BPSK & QPSK.)
tone_phase += tone_delta; // In periodic signals(Sine/triangle/square) we are using to FM mod. in BPSK-QSPK we are using to calculate each 1/4 of the periode.
if (tone_shape != 5) { // All periodic except Pseudo Random White Noise.
tone_phase += tone_delta; // In periodic signals we are using phase to generate the tone to be modulated.
}
if (tone_shape < 7) { // All Option shape signals except BPSK(7) & QPSK(8) we are modulating in FM. (Those two has phase shift modulation XPSK , not FM )
if (modulation == 1) {
// Do FM modulation
delta = sample * fm_delta;
@@ -130,6 +133,21 @@ void SigGenProcessor::execute(const buffer_c8_t& buffer) {
re = (sine_table_i8[(sphase & 0xFF000000) >> 24]); // sin LUT is not dealing with decimals , output range [-128 ,...127]
im = (sine_table_i8[(phase & 0xFF000000) >> 24]);
} else if (modulation == 4) {
// Do Double Side Band modulation
re = sample;
im = 0;
} else if (modulation == 5) {
// Do AM modulation (100% mod index)
re = (127 >> 1) + (sample >> 1);
im = 0;
} else if (modulation == 6) {
// Do AM modulation (50% mod index)
re = 95 + (sample >> 2);
im = 0;
}
}
@@ -154,7 +172,8 @@ void SigGenProcessor::on_message(const Message* const msg) {
auto_off = false;
fm_delta = message.bw * (0xFFFFFFULL / 1536000);
tone_shape = message.shape;
tone_shape = message.shape & 0xF;
modulation = (message.shape & 0xF0) >> 4;
// lfsr = seed_value ; // Finally not used , init lfsr 8 bits.
lfsr_16 = seed_value_16; // init lfsr 16 bits.
+1 -1
View File
@@ -36,7 +36,7 @@ class SigGenProcessor : public BasebandProcessor {
bool configured{false};
uint32_t tone_delta{0}, fm_delta{}, tone_phase{0};
uint8_t tone_shape{};
uint8_t tone_shape{}, modulation{};
uint32_t sample_count{0};
bool auto_off{};
int32_t phase{0}, sphase{0}, delta{0}; // they may have sign in the pseudo random sample generation.
@@ -1060,6 +1060,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste
}
}
/* go to default */
__attribute__ ((fallthrough));
#endif
default:
val = 1; /* Internal error */
@@ -212,7 +212,7 @@ struct data_t {
bool updown_frequency_rx_correction;
bool updown_frequency_tx_correction;
bool lcd_inverted_mode : 1;
bool UNUSED_5 : 1;
bool encoder_dial_direction : 1; // false = normal, true = reverse
bool UNUSED_6 : 1;
bool UNUSED_7 : 1;
@@ -290,7 +290,7 @@ struct data_t {
updown_frequency_rx_correction(false),
updown_frequency_tx_correction(false),
lcd_inverted_mode(false),
UNUSED_5(false),
encoder_dial_direction(false),
UNUSED_6(false),
UNUSED_7(false),
@@ -417,7 +417,8 @@ void defaults() {
set_config_splash(true);
set_config_disable_external_tcxo(false);
set_encoder_dial_sensitivity(DIAL_SENSITIVITY_NORMAL);
set_config_speaker_disable(true); // Disable AK4951 speaker by default (in case of OpenSourceSDRLab H2)
set_encoder_dial_direction(false); // false = normal, true = reverse
set_config_speaker_disable(true); // Disable AK4951 speaker by default (in case of OpenSourceSDRLab H2)
set_menu_color(Color::grey());
set_ui_hide_numeric_battery(true); // hide the numeric battery by default - no space to display it
@@ -1080,6 +1081,13 @@ void set_encoder_rate_multiplier(uint8_t v) {
data->encoder_rate_multiplier = v;
}
bool encoder_dial_direction() {
return data->encoder_dial_direction;
}
void set_encoder_dial_direction(bool v) {
data->encoder_dial_direction = v;
}
// Recovery mode magic value storage
static data_t* data_direct_access = reinterpret_cast<data_t*>(memory::map::backup_ram.base());
@@ -1246,6 +1254,7 @@ bool debug_dump() {
pmem_dump_file.write_line("frequency_tx_correction: " + to_string_dec_uint(data->frequency_tx_correction));
pmem_dump_file.write_line("encoder_dial_sensitivity: " + to_string_dec_uint(data->encoder_dial_sensitivity));
pmem_dump_file.write_line("encoder_rate_multiplier: " + to_string_dec_uint(data->encoder_rate_multiplier));
pmem_dump_file.write_line("encoder_dial_direction: " + to_string_dec_uint(data->encoder_dial_direction)); // 0 = normal, 1 = reverse
pmem_dump_file.write_line("headphone_volume_cb: " + to_string_dec_int(data->headphone_volume_cb));
pmem_dump_file.write_line("config_mode_storage: 0x" + to_string_hex(data->config_mode_storage, 8));
pmem_dump_file.write_line("dst_config: 0x" + to_string_hex((uint32_t)data->dst_config.v, 8));
@@ -252,6 +252,8 @@ uint8_t encoder_dial_sensitivity();
void set_encoder_dial_sensitivity(uint8_t v);
uint8_t encoder_rate_multiplier();
void set_encoder_rate_multiplier(uint8_t v);
bool encoder_dial_direction();
void set_encoder_dial_direction(bool v);
uint32_t config_mode_storage_direct();
void set_config_mode_storage_direct(uint32_t v);
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.16)
project(standalone_apps)
+1
View File
@@ -0,0 +1 @@
__pycache__/
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
for fname in $(ls ../graphics/); do
fname=$(echo "$fname" | awk -F'.' '{print $1}')
out=$(grep -r --exclude="bitmap.hpp" "$fname" ../* )
ret=$?
if [[ "$ret" -ne 0 ]]; then
echo "$fname not found"
fi
done
@@ -0,0 +1,265 @@
# Copyleft Whiterose from the Dark Army
#
# 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.
# this tool allow you flash pp and copy the apps in fastest way. note that you need to have a sdcard switcher to switch sdcard to pc.
# although, if you don't have one, you still can take out the sdcard and plug it into your pc, but i think it would not pretty fast.
#!/usr/bin/env python3
import sys
import glob
import serial
import serial.tools.list_ports
import os
import shutil
import time
import subprocess
import tempfile
# config
SUDO_PASSWORD = ""
SDCARD_LABEL = "portapack"
def write_command(ser, command, wait_response=None, remove_echo=False, dont_wait_ch=False):
# clean buffer
while True:
try:
if ser.in_waiting:
ser.read(ser.in_waiting)
else:
break
except:
break
command_with_newline = command + "\r\n"
try:
ser.write(command_with_newline.encode())
except Exception as e:
return f"write err: {str(e)}"
response = ""
expected_echo = f"{command}\r\n"
wait_response_met = wait_response is None
while True:
try:
if ser.in_waiting:
msg = ser.read(ser.in_waiting).decode('utf-8')
response += msg
if wait_response and wait_response in response:
wait_response_met = True
if wait_response_met and (dont_wait_ch or "ch> " in response):
if remove_echo:
return response.replace(expected_echo, "")
return response
except serial.SerialTimeoutException:
continue
except Exception as e:
return f"e: {str(e)}"
def get_serial_devices():
ports = serial.tools.list_ports.comports()
if not ports:
print("no serial device found")
return None
portapack_device = None
for port in ports:
if port.product == "PortaPack Mayhem":
print(f"found your pp:")
print(f"device: {port.device}")
print(f"description: {port.description}")
print(f"hwid: {port.hwid}")
if port.manufacturer:
print(f"manufacturer: {port.manufacturer}")
if port.serial_number:
print(f"serial_number: {port.serial_number}")
portapack_device = port
break
if not portapack_device:
print("no pp device found")
return portapack_device
def run_sudo_command(cmd):
if not SUDO_PASSWORD:
print("sudo password not set, please hard code it in the script")
return
try:
process = subprocess.Popen(
['sudo', '-S'] + cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
stdout, stderr = process.communicate(input=SUDO_PASSWORD + '\n')
if process.returncode != 0:
raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
return stdout
except subprocess.CalledProcessError as e:
print(f"sudo command failed: {e}")
raise
def get_pp_device_linux():
try:
cmd = ["lsblk", "-o", "NAME,LABEL,FSTYPE,SIZE,MOUNTPOINT", "-n", "-p"]
result = subprocess.run(cmd, capture_output=True, text=True)
# find your pp sd
for line in result.stdout.splitlines():
clean_line = line.replace('└─', '').replace('├─', '').strip()
parts = clean_line.split()
if len(parts) >= 2 and SDCARD_LABEL in parts[1]: # checker
device_path = parts[0]
# if path valid
if not os.path.exists(device_path):
continue
# if mounted, return mountpoint
if len(parts) >= 5:
mountpoint = parts[4]
return device_path, mountpoint
# if not, create temp dir and mount
mount_point = tempfile.mkdtemp()
print(f"mount {device_path} to {mount_point}")
run_sudo_command(["mount", "-o", f"uid={os.getuid()},gid={os.getgid()}", device_path, mount_point])
return device_path, mount_point
return None, None
except subprocess.CalledProcessError as e:
print(f"command failed: {str(e)}")
return None, None
def wait_for_pp_drive():
while True:
if os.name == 'nt': # win didn't test yet, TODO
drives = [d + ':' for d in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if os.path.exists(d + ':')]
for drive in drives:
if os.path.basename(os.path.abspath(drive)).lower() == SDCARD_LABEL:
return drive, None
else: # linux and mac
device_path, mount_point = get_pp_device_linux()
if device_path and mount_point:
return mount_point, device_path
time.sleep(1)
def run():
# worker 1: check device connected
device = get_serial_devices()
if not device:
print("no pp device found")
return
try:
# worker 2: open serial and send hackrf cmd
ser = serial.Serial(device.device, baudrate=115200, timeout=1)
for i in range(2):
write_command(ser, "hackrf")
ser.close()
# worker 3: hint user to swtich sdcard to pc
print("\033[92m\n\t+------------------------+")
print("\t| switch PP sdcard to PC |")
print("\t+------------------------+\033[0m")
print("wait PP sdcard...")
# worker 4: wait pp sd
mount_point, device_path = wait_for_pp_drive()
if not mount_point:
print("no pp sd found")
return
print(f"find pp sd: {mount_point}")
# worker 5: copy ppma and ppmp apps
apps_dir = os.path.join(mount_point, 'APPS')
if not os.path.exists(apps_dir):
os.makedirs(apps_dir)
firmware_dir = os.path.join('.', 'firmware', 'application')
for ext in ['ppma', 'ppmp']:
for file in glob.glob(os.path.join(firmware_dir, f'*.{ext}')):
dest = os.path.join(apps_dir, os.path.basename(file))
print(f"cp: {os.path.basename(file)}")
shutil.copy2(file, dest)
print("apps copy done")
# worker 6: umount pp sd
if os.name != 'nt' and device_path:
run_sudo_command(["umount", mount_point])
os.rmdir(mount_point) # 删除临时挂载点
# worker 7: run flash cmd with hackrf_spiflash util
print("\nflash...")
process = subprocess.Popen(
["hackrf_spiflash", "-w", "./firmware/portapack-mayhem-firmware.bin"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
while True:
output = process.stdout.readline()
if output:
print(output.strip())
if process.poll() is not None:
break
if process.returncode != 0:
raise subprocess.CalledProcessError(process.returncode, "hackrf_spiflash")
# worker 8: hint user to swtich sdcard switcher back to pp
print("\033[92m\n\t+------------------------------------------------+")
print("\t| switch sdcard switcher back to pp, then reboot |")
print("\t+------------------------------------------------+\033[0m")
except serial.SerialException as e:
print(f"serial comm error: {str(e)}")
except OSError as e:
print(f"file operation error: {str(e)}")
except subprocess.CalledProcessError as e:
print(f"system command error: {str(e)}")
except Exception as e:
print(f"error: {str(e)}")
# ensure umount when error
if os.name != 'nt' and 'mount_point' in locals() and device_path:
try:
run_sudo_command(["umount", mount_point])
os.rmdir(mount_point)
except:
pass
if __name__ == "__main__":
try:
run()
except Exception as e:
print(f"error: {str(e)}")
sys.exit(1)
@@ -53,7 +53,7 @@ AboutView::AboutView(NavigationView& nav) {
button_ok.focus();
};
for (auto& authors_line : authors_list) {
for (auto& authors_line : mayhem_information_list) {
// if it's starting with #, it's a title and we have to substract the '#' and paint yellow
if (authors_line.size() > 0) {
if (authors_line[0] == '#') {
@@ -84,15 +84,13 @@ void AboutView::on_frame_sync() {
menu_view.set_highlighted(current + 1);
} else {
menu_view.set_highlighted(0);
// ^ to go back to the REAL top instead of make the 2 at the top to make the title disappeares
menu_view.set_highlighted(2); // the first line that has human name
}
}
}
void AboutView::focus() {
button_ok.focus();
menu_view.set_highlighted(2); // the first line that has human name
menu_view.set_highlighted(3); // contributors block starting line
}
bool AboutView::on_touch(const TouchEvent) {
@@ -141,8 +139,12 @@ def get_contributors(url):
def generate_content(projects):
project_contrib = []
project_contrib.append("string_view authors_list[] = {\n")
project_contrib.append(" \"# * List of contributors * \",\n")
project_contrib.append("string_view mayhem_information_list[] = {\n")
project_contrib.append(" \"#****** Mayhem Community ******\",\n")
project_contrib.append(" \" \",\n")
project_contrib.append(" \" https://discord.mayhem.app\",\n")
project_contrib.append(" \" \",\n")
project_contrib.append(" \"#**** List of contributors ****\",\n")
for project in projects:
project_contrib.append(" \" \",\n")
project_contrib.append(f" \"#{project[0]}:\",\n")
@@ -170,7 +172,7 @@ def pp_create_ui_about_simple_cpp(cpp_file, cppheader, cppcontent, cppfooter):
def pp_change_ui_about_simple_cpp(cpp_file, cppcontent):
content = []
content_pattern = re.compile(r"string_view authors_list\[\] = {\n(?:\s+(?:.*,\n)+\s+.*};\n)", re.MULTILINE)
content_pattern = re.compile(r"string_view mayhem_information_list\[\] = {\n(?:\s+(?:.*,\n)+\s+.*};\n)", re.MULTILINE)
# Read original file
with open(cpp_file, 'r') as file:
+20
View File
@@ -161,3 +161,23 @@ write_image(spi_image, output_path)
percent_remaining = round(1000 * pad_size / spi_size) / 10;
print("Space remaining in flash ROM:", pad_size, "bytes (", percent_remaining, "%)")
# copy the fast flash script
build_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'build')
flash_py_path = os.path.join(build_dir, 'flash.py')
if not os.path.exists(flash_py_path):
current_dir = os.path.dirname(__file__)
source_file = os.path.join(current_dir, 'fast_flash_pp_and_copy_apps.py')
if not os.path.exists(build_dir):
os.makedirs(build_dir)
# cp
import shutil
print(f"\ncopy {source_file} to {flash_py_path}\n")
shutil.copy2(source_file, flash_py_path)
+10
View File
@@ -0,0 +1,10 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok650Async
Protocol: RAW
RAW_Data: 210 650 210 650 210 650 630 650 210 650 210 650 210 650 630 650
RAW_Data: 210 650 210 650 210 650 630 650 210 650 210 650 210 650 210 1950
RAW_Data: 210 650 210 650 210 650 630 650 210 650 210 650 210 650 630 650
RAW_Data: 210 650 210 650 210 650 630 650 210 650 210 650 210 650 210 1950