Compare commits

...

22 Commits

Author SHA1 Message Date
sommermorgentraum 809abb6842 user can disable battery change hint (#2612)
* theme fix again

* _

* _
2025-04-06 10:24:50 +08:00
sommermorgentraum 31082c63af theme fix again (#2611)
* theme fix again

* _
2025-04-05 16:58:12 +08:00
gullradriel ff14008b43 prevent long life var for audio app - AM (#2610)
* static vars so no external linkage is possible

* persistent settings and no more global living variables

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
2025-04-04 21:43:26 +08:00
sommermorgentraum 1377516dce make the ptext_prompt func can define which keyboard to enter (#2608)
* _

* format

* use define
2025-04-04 15:41:12 +02:00
Brumi-2021 4162820409 solving_Audio_App_AM_GUI_Problem_issue_2604 (#2609) 2025-04-04 14:04:06 +02:00
sommermorgentraum 4bbe1175c1 add tap tempo to metronomic app (#2605)
* _

* format

* fix new tree in Arch
2025-04-02 22:15:12 +02:00
sommermorgentraum ecd1a217d7 Issue template again (#2602)
* test1

* test2
2025-03-27 10:12:43 +01:00
RocketGod 335cace137 Remove RF TX and use PATX baseband for audio --> speaker out only (#2601)
* Force 433.92 and remove metadata check

We already know the frequency for all files so don't need a million metadata files to match.

* Remove RF TX. Improve PATX baseband.

* code formatting of course
2025-03-27 12:33:24 +08:00
Mark Thompson dbd708a1c7 Added more Wefax stations (#2600)
* Delete sdcard/FREQMAN/WEFAX.TXT

Replace with 2 files

* Add more WeFax frequencies

* Update comments

* Oops wrong folder

* Oops wrong folder

* Change comments
2025-03-26 11:43:17 -05:00
RocketGod 4d842b5fae Force 433.92 and remove metadata check (#2599)
* Force 433.92 and remove metadata check: we already know the frequency for all files so don't need a million metadata files to match.
* Variable fixes and move to header
2025-03-26 15:56:27 +01:00
Erwin Ried e24f1b131d Create CONTRIBUTING.md (#2598) 2025-03-26 19:53:41 +08:00
Erwin Ried 3f2c7351f1 Create SECURITY.md 2025-03-26 12:22:18 +01:00
Erwin Ried afc75f6cda Create pull_request_template.md 2025-03-26 12:20:54 +01:00
Erwin Ried 69b17faddf Create CODE_OF_CONDUCT.md 2025-03-26 12:09:51 +01:00
gullradriel 2c118ae584 Remove unneeded AMFM support in those apps (#2597) 2025-03-26 11:58:11 +01:00
gullradriel 75c34747cb Externalize level (#2596)
* removing ability to focus on RSSI bars and to launch level app, until a solution to launch external apps from internal ones is given
* externalize Level app
2025-03-26 18:20:01 +08:00
gullradriel 7754c0f37f Externalize scanner (#2589)
* externalize scanner
* NFM as main baseband as it's the biggest used one
* fix modulation bug introduced with AMFM
2025-03-26 10:42:24 +01:00
sommermorgentraum 37cc35d3c6 move default splash into sdcard (#2595)
* move bmps to sdcard
* remove unrelated files
* gitignore
* credit
* format
2025-03-26 10:34:00 +01:00
gullradriel 8a7aa9c0f8 remove not yet enabled screening app (#2594) 2025-03-25 20:20:52 +08:00
Totoo 22d6e34cd6 remove dead code (#2593) 2025-03-25 12:33:28 +01:00
gullradriel 2229381ce3 Externalize dump pmem (#2590)
* initial commit

* clang

* memory icon

* text output and exit button, FOCUS OVERRIDE TO AVOID COMPILATION ERROR

* modem and data_structure_version accessor

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
2025-03-24 18:14:08 -05:00
RocketGod 4a63bdd7a0 Fixed the I Tetromino rotation using SRS (Super Rotation System) (#2588) 2025-03-24 14:43:12 +01:00
80 changed files with 1466 additions and 1020 deletions
@@ -2,6 +2,7 @@ name: Hardware / QC / QA / selling
description: Issues that related with hardware, quality control, quality assurance, selling, etc.
labels:
- question
- hardware problem
body:
- type: markdown
attributes:
@@ -11,9 +12,6 @@ body:
We would like to inform you that we can't provide much help regarding hardware/QC/QA/selling issues because we are not controlling various vendors/manufacturers, and also we are not profiting from you buying your device.
You are still welcome to ask, but please be aware that for this kind of issue, ask the seller would be the best option.
> [!IMPORTANT]
If you are a seller/vendor and your customer has directed you to this page as a reference/evidence of a "broken device" or similar issue, please be aware that we are not providing any "official guarantee of a faulty device." We are only offering suggestions based on what the submitter has stated. We do not guarantee that the device is broken or anything else.
- type: textarea
id: description
attributes:
@@ -0,0 +1,20 @@
name: Hardware Issue Warning
on:
issues:
types: [labeled]
jobs:
add-comment:
if: github.event.label.name == 'hardware problem'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Add warning comment
uses: peter-evans/create-or-update-comment@v3
with:
issue-number: ${{ github.event.issue.number }}
body: |
> [!IMPORTANT]
If you are a seller/vendor and your customer has directed you to this page as a reference/evidence of a "broken device" or similar issue, please be aware that we are not providing any "official guarantee of a faulty device." We are only offering suggestions based on what the submitter has stated. We do not guarantee that the device is broken or anything else.
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
https://github.com/portapack-mayhem/mayhem-firmware/issues/new/.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+1
View File
@@ -0,0 +1 @@
Please see [How-to-collaborate](https://github.com/portapack-mayhem/mayhem-firmware/wiki/How-to-collaborate)
+3 -1
View File
@@ -9,7 +9,9 @@
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.
[<img src="https://github.com/user-attachments/assets/dea337ab-fb64-4a2a-b419-69afd272e815" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#new-h4m-mayhem-edition) [<img src="https://camo.githubusercontent.com/5c1f1da0688240ac7b2ccca0c8dbfd1d73f2540741ad8b1828ba4d5ea68af248/68747470733a2f2f6769746875622d70726f64756374696f6e2d757365722d61737365742d3632313064662e73332e616d617a6f6e6177732e636f6d2f343339333937392f3239353533323731382d38653562363631632d663934362d346365652d386232642d3061363135663737313566342e706e67" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#h2m-mayhem-edition)
[<img src="https://github.com/user-attachments/assets/dea337ab-fb64-4a2a-b419-69afd272e815" height="310">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#new-h4m-mayhem-edition)
[<img src="https://camo.githubusercontent.com/5c1f1da0688240ac7b2ccca0c8dbfd1d73f2540741ad8b1828ba4d5ea68af248/68747470733a2f2f6769746875622d70726f64756374696f6e2d757365722d61737365742d3632313064662e73332e616d617a6f6e6177732e636f6d2f343339333937392f3239353533323731382d38653562363631632d663934362d346365652d386232642d3061363135663737313566342e706e67" height="310">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#h2m-mayhem-edition)
[<img src="https://camo.githubusercontent.com/c1f7dd1e7672324f60a513f0de23de76da6a669e63896a9de535d8c8093fc3c7/68747470733a2f2f7261772e6769746875622e636f6d2f7368617265627261696e65642f706f7274617061636b2d6861636b72662f6d61737465722f646f632f696d616765732f68617264776172652f706f7274617061636b5f68315f6f7065726174696e672e6a7067" height="310">]([https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#h2m-mayhem-edition](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions#h1r1r2))
# What is this?
+1
View File
@@ -0,0 +1 @@
Please check [Intended-Use-and-Legality](https://github.com/portapack-mayhem/mayhem-firmware/wiki/)
-3
View File
@@ -191,7 +191,6 @@ set(CPPSRC
clock_manager.cpp
core_control.cpp
database.cpp
de_bruijn.cpp
rfm69.cpp
event_m0.cpp
file_reader.cpp
@@ -294,7 +293,6 @@ set(CPPSRC
apps/ui_flash_utility.cpp
apps/ui_freqman.cpp
apps/ui_iq_trim.cpp
apps/ui_level.cpp
apps/ui_looking_glass_app.cpp
apps/ui_mictx.cpp
apps/ui_modemsetup.cpp
@@ -303,7 +301,6 @@ set(CPPSRC
apps/ui_rds.cpp
apps/ui_recon_settings.cpp
apps/ui_recon.cpp
# apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp
apps/ui_search.cpp
apps/ui_settings.cpp
+23 -7
View File
@@ -52,20 +52,20 @@ AMOptionsView::AMOptionsView(
&zoom_config,
});
zoom_config.on_change = [this, view](size_t, OptionsField::value_t n) {
receiver_model.set_am_configuration(previous_filter_array_index + n);
zoom_config.on_change = [this, view](size_t, OptionsField::value_t n) { // n , has two option values. when GUI =zoom+1 => (0), when GUI=zoom+2 (6)
receiver_model.set_am_configuration(view->get_previous_AM_mode_option() + n); // n (0 or 6)
view->set_zoom_factor(AM_MODULATION, n);
view->set_previous_zoom_option(n);
};
// restore zoom selection
zoom_config.set_by_value(view->get_zoom_factor(AM_MODULATION));
freqman_set_bandwidth_option(AM_MODULATION, options_config); // adding the common message from freqman.cpp to the options_config
options_config.set_by_value(receiver_model.am_configuration());
freqman_set_bandwidth_option(AM_MODULATION, options_config); // freqman.cpp to the options_config, only allowing 5 modes freqman_bandwidths[AM] {"DSB 9k", 0}, {"DSB 6k", 1}, {"USB+3k", 2}, {"LSB-3k", 3}, {"CW", 4},
options_config.set_by_value(receiver_model.am_configuration() - view->get_previous_zoom_option()); // restore AM GUI option mode , AM FIR index filters (0..11) values , <baseband::AMConfig, 12> am_configs has 12 fir index elements.
options_config.on_change = [this, view](size_t, OptionsField::value_t n) {
receiver_model.set_am_configuration(n);
previous_filter_array_index = n;
zoom_config.set_by_value(view->get_zoom_factor(AM_MODULATION));
receiver_model.set_am_configuration(n + view->get_previous_zoom_option()); // we select proper FIR AM filter (0..11), = 0..4 GUI AM modes + offset +6 (if zoom+2)
view->set_previous_AM_mode_option(n); // (0..4) allowing 5 AM modes (DSB9K, DSB6K, USB,LSB, CW)
};
}
@@ -282,6 +282,22 @@ void AnalogAudioView::set_zoom_factor(uint8_t mode, uint8_t zoom) { // define a
zoom_factor_amfm = zoom;
}
uint8_t AnalogAudioView::get_previous_AM_mode_option() {
return previous_AM_mode_option;
}
void AnalogAudioView::set_previous_AM_mode_option(uint8_t mode) {
previous_AM_mode_option = mode;
}
uint8_t AnalogAudioView::get_previous_zoom_option() {
return previous_zoom;
}
void AnalogAudioView::set_previous_zoom_option(uint8_t zoom) {
previous_zoom = zoom;
}
uint8_t AnalogAudioView::get_spec_iq_phase_calibration_value() { // define accessor functions inside AnalogAudioView to read iq_phase_calibration_value
return iq_phase_calibration_value;
}
+12 -2
View File
@@ -40,7 +40,6 @@ class AnalogAudioView;
class AMOptionsView : public View {
public:
AMOptionsView(AnalogAudioView* view, Rect parent_rect, const Style* style);
int16_t previous_filter_array_index = 0;
private:
Text label_config{
@@ -59,7 +58,7 @@ class AMOptionsView : public View {
{23 * 8, 0 * 16},
7,
{{"ZOOM x1", 0},
{"ZOOM x2", 6}} // offset index array filters.
{"ZOOM x2", 6}} // offset index AM modes array FIR filters.
};
};
@@ -200,6 +199,12 @@ class AnalogAudioView : public View {
uint8_t get_zoom_factor(uint8_t mode);
void set_zoom_factor(uint8_t mode, uint8_t zoom);
uint8_t get_previous_AM_mode_option();
void set_previous_AM_mode_option(uint8_t mode);
uint8_t get_previous_zoom_option();
void set_previous_zoom_option(uint8_t zoom);
private:
static constexpr ui::Dim header_height = 3 * 16;
@@ -208,6 +213,9 @@ class AnalogAudioView : public View {
uint8_t iq_phase_calibration_value{15}; // initial default RX IQ phase calibration value , used for both max2837 & max2839
uint8_t zoom_factor_am{0}; // initial zoom factor in AM mode
uint8_t zoom_factor_amfm{0}; // initial zoom factor in AMFM mode
uint8_t previous_AM_mode_option{0}; // GUI 5 AM modes : (0..4 ) (DSB9K, DSB6K, USB,LSB, CW). Used to select proper FIR filter (0..11) AM mode + offset 0 (zoom+1) or +6 (if zoom+2)
uint8_t previous_zoom{0}; // GUI ZOOM+1, ZOOM+2 , equivalent to two values offset 0 (zoom+1) or +6 (if zoom+2)
//
app_settings::SettingsManager settings_{
"rx_audio",
app_settings::Mode::RX,
@@ -215,6 +223,8 @@ class AnalogAudioView : public View {
{"iq_phase_calibration"sv, &iq_phase_calibration_value}, // we are saving and restoring that CAL from Settings.
{"zoom_factor_am"sv, &zoom_factor_am}, // we are saving and restoring AM ZOOM factor from Settings.
{"zoom_factor_amfm"sv, &zoom_factor_amfm}, // we are saving and restoring AMFM ZOOM factor from Settings.
{"previous_AM_mode_option"sv, &previous_AM_mode_option}, // we are saving and restoring AMFM ZOOM factor from Settings.
{"previous_zoom"sv, &previous_zoom}, // we are saving and restoring AMFM ZOOM factor from Settings.
}};
const Rect options_view_rect{0 * 8, 1 * 16, 30 * 8, 1 * 16};
+3
View File
@@ -203,6 +203,7 @@ BleRecentEntryDetailView::BleRecentEntryDetailView(NavigationView& nav, const Bl
nav,
packetFileBuffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this, packetToSave](std::string& buffer) {
on_save_file(buffer, packetToSave);
});
@@ -471,6 +472,7 @@ BLERxView::BLERxView(NavigationView& nav)
nav_,
filterBuffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
on_filter_change(buffer);
});
@@ -493,6 +495,7 @@ BLERxView::BLERxView(NavigationView& nav)
nav,
listFileBuffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
on_save_file(buffer);
});
+1
View File
@@ -399,6 +399,7 @@ BLETxView::BLETxView(NavigationView& nav)
nav,
packetFileBuffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
on_save_file(buffer);
});
+1
View File
@@ -94,6 +94,7 @@ APRSTXView::APRSTXView(NavigationView& nav) {
nav,
payload,
30,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& s) {
text_payload.set(s);
});
-1
View File
@@ -419,7 +419,6 @@ void DebugMenuView::on_populate() {
}
add_items({
{"Buttons Test", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_controls, [this]() { nav_.push<DebugControlsView>(); }},
{"Debug Dump", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_memory, [this]() { portapack::persistent_memory::debug_dump(); }},
{"M0 Stack Dump", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_memory, [this]() { stack_dump(); }},
{"Memory Dump", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_memory, [this]() { nav_.push<DebugMemoryDumpView>(); }},
{"Peripherals", ui::Theme::getInstance()->fg_darkcyan->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<DebugPeripheralsMenuView>(); }},
@@ -25,7 +25,6 @@
#include "ui_transmitter.hpp"
#include "transmitter_model.hpp"
#include "encoders.hpp"
#include "de_bruijn.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
+5 -5
View File
@@ -499,7 +499,7 @@ FileSaveView::FileSaveView(
button_edit_path.on_select = [this](Button&) {
buffer_ = path_.string();
text_prompt(nav_, buffer_, max_filename_length,
text_prompt(nav_, buffer_, max_filename_length,ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string&) {
path_ = buffer_;
refresh_widgets();
@@ -508,7 +508,7 @@ FileSaveView::FileSaveView(
button_edit_name.on_select = [this](Button&) {
buffer_ = file_.string();
text_prompt(nav_, buffer_, max_filename_length,
text_prompt(nav_, buffer_, max_filename_length,ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string&) {
file_ = buffer_;
refresh_widgets();
@@ -566,7 +566,7 @@ void FileManagerView::on_rename(std::string_view hint) {
cursor_pos = pos;
text_prompt(
nav_, name_buffer, cursor_pos, max_filename_length,
nav_, name_buffer, cursor_pos, max_filename_length, ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& renamed) {
auto renamed_path = fs::path{renamed};
rename_file(get_selected_full_path(), current_path / renamed_path);
@@ -640,7 +640,7 @@ void FileManagerView::on_clean() {
void FileManagerView::on_new_dir() {
name_buffer = "";
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) {
text_prompt(nav_, name_buffer, max_filename_length, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& dir_name) {
make_new_directory(current_path / dir_name);
reload_current(true);
});
@@ -671,7 +671,7 @@ void FileManagerView::on_paste() {
void FileManagerView::on_new_file() {
name_buffer = "";
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& file_name) {
text_prompt(nav_, name_buffer, max_filename_length, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& file_name) {
make_new_file(current_path / file_name);
reload_current(true);
});
+2 -2
View File
@@ -240,7 +240,7 @@ void FrequencyManagerView::on_edit_freq() {
void FrequencyManagerView::on_edit_desc() {
temp_buffer_ = current_entry().description;
text_prompt(nav_, temp_buffer_, freqman_max_desc_size, [this](std::string& new_desc) {
text_prompt(nav_, temp_buffer_, freqman_max_desc_size, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& new_desc) {
auto entry = current_entry();
entry.description = std::move(new_desc);
db_.replace_entry(current_index(), entry);
@@ -250,7 +250,7 @@ void FrequencyManagerView::on_edit_desc() {
void FrequencyManagerView::on_add_category() {
temp_buffer_.clear();
text_prompt(nav_, temp_buffer_, 20, [this](std::string& new_name) {
text_prompt(nav_, temp_buffer_, 20, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& new_name) {
if (!new_name.empty()) {
create_freqman_file(new_name);
refresh_categories();
+1 -1
View File
@@ -153,7 +153,7 @@ void POCSAGTXView::paint(Painter&) {
}
void POCSAGTXView::on_set_text(NavigationView& nav) {
text_prompt(nav, buffer, MAX_POCSAG_LENGTH);
text_prompt(nav, buffer, MAX_POCSAG_LENGTH, ENTER_KEYBOARD_MODE_ALPHA);
}
POCSAGTXView::POCSAGTXView(
+2
View File
@@ -65,6 +65,7 @@ RDSPSNView::RDSPSNView(
nav,
PSN,
8,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& s) {
text_psn.set(s);
});
@@ -86,6 +87,7 @@ RDSRadioTextView::RDSRadioTextView(
nav,
radiotext,
28,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& s) {
text_radiotext.set(s);
});
+10 -16
View File
@@ -517,11 +517,7 @@ ReconView::ReconView(NavigationView& nav)
};
set_loop_config(continuous);
rssi.set_focusable(true);
rssi.set_peak(true, 500);
rssi.on_select = [this](RSSI&) {
nav_.replace<LevelView>();
};
// TODO: *BUG* Both transmitter_model and receiver_model share the same pmem setting for target_frequency.
button_mic_app.on_select = [this](Button&) {
@@ -1227,16 +1223,6 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
text_ctcss.set(" ");
recording_sampling_rate = 48000;
break;
case AMFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt);
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
field_bw.set_by_value(0);
text_ctcss.set(" ");
recording_sampling_rate = 12000;
break;
case SPEC_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_capture);
@@ -1267,9 +1253,17 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
field_mode.set_selected_index(new_mod);
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) {
change_mode(v);
// initialize to a value under SPEC
static freqman_index_t last_mode = WFM_MODULATION;
if (v > SPEC_MODULATION) {
if (last_mode == SPEC_MODULATION)
v = AM_MODULATION;
else
v = SPEC_MODULATION;
field_mode.set_selected_index(v);
}
last_mode = v;
change_mode(v);
};
// for some motive, audio output gets stopped.
if (!recon && field_mode.selected_index_value() != SPEC_MODULATION)
-1
View File
@@ -31,7 +31,6 @@
#include "analog_audio_app.hpp"
#include "audio.hpp"
#include "ui_mictx.hpp"
#include "ui_level.hpp"
#include "ui_looking_glass_app.hpp"
#include "portapack_persistent_memory.hpp"
#include "baseband_api.hpp"
@@ -82,7 +82,7 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
};
button_choose_output_name.on_select = [this, &nav](Button&) {
text_prompt(nav, _output_file, 28, [this](std::string& buffer) {
text_prompt(nav, _output_file, 28, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& buffer) {
_output_file = buffer;
button_choose_output_name.set_text(_output_file);
});
+4 -1
View File
@@ -1044,12 +1044,14 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
add_children({&labels,
&button_save,
&button_cancel,
&checkbox_overridebatt});
&checkbox_overridebatt,
&checkbox_battery_charge_hint});
if (i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055)) add_children({&button_reset, &labels2});
button_save.on_select = [&nav, this](Button&) {
pmem::set_ui_override_batt_calc(checkbox_overridebatt.value());
pmem::set_ui_battery_charge_hint(checkbox_battery_charge_hint.value());
battery::BatteryManagement::set_calc_override(checkbox_overridebatt.value());
send_system_refresh();
nav.pop();
@@ -1064,6 +1066,7 @@ SetBatteryView::SetBatteryView(NavigationView& nav) {
};
checkbox_overridebatt.set_value(pmem::ui_override_batt_calc());
checkbox_battery_charge_hint.set_value(pmem::ui_battery_charge_hint());
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
+13 -4
View File
@@ -978,9 +978,13 @@ class SetBatteryView : public View {
int32_t selected = 0;
Labels labels{
{{1 * 8, 1 * 16}, "Override batt calculation", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 2 * 16}, "method to voltage based", Theme::getInstance()->fg_light->foreground}};
Labels labels2{
{{1 * 8, 6 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}};
{{1 * 8, 2 * 16}, "method to voltage based", Theme::getInstance()->fg_light->foreground},
/**/
{{1 * 8, 6 * 16}, "Display a hint to remind you", Theme::getInstance()->fg_light->foreground},
{{1 * 8, 7 * 16}, "when you charge", Theme::getInstance()->fg_light->foreground}};
Labels labels2{{{1 * 8, 11 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
@@ -990,13 +994,18 @@ class SetBatteryView : public View {
23,
"Override"};
Checkbox checkbox_battery_charge_hint{
{2 * 8, 9 * 16},
23,
"Charge hint"};
Button button_cancel{
{16 * 8, 16 * 16, 12 * 8, 32},
"Cancel",
};
Button button_reset{
{2 * 8, 8 * 16, 12 * 8, 32},
{2 * 8, 13 * 16, 12 * 8, 32},
"Reset",
};
};
@@ -617,6 +617,7 @@ void TextEditorView::show_edit_line() {
edit_line_buffer_,
viewer.col(),
max_edit_length,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
auto range = file_->line_range(viewer.line());
if (!range)
+2 -1
View File
@@ -25,6 +25,7 @@
#include "ui.hpp"
#include "ui_navigation.hpp"
#include "ui_widget.hpp"
#include "ui_textentry.hpp"
namespace ui {
@@ -105,7 +106,7 @@ void bind(TextField& field, T& value, NavigationView& nav, Fn fn = Fn{}) {
// Capture a new string and make the lambda mutable so it can be modified.
field.on_select = [&nav, buf = std::string{}](TextField& tf) mutable {
buf = tf.get_text();
text_prompt(nav, buf, /*max_length*/ 255,
text_prompt(nav, buf, /*max_length*/ 255, ENTER_KEYBOARD_MODE_ALPHA,
[&tf](std::string& str) {
tf.set_text(str);
});
@@ -1,72 +0,0 @@
unsigned char modal_warning_bmp[] = {
0x42, 0x4d, 0xfa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00,
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0xa8, 0x02,
0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x00, 0x00, 0x5a,
0xff, 0x00, 0x78, 0x78, 0x78, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0xa9,
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x02, 0x03, 0x24, 0x66, 0x02, 0x30,
0x00, 0x00, 0x02, 0x36, 0x24, 0x66, 0x02, 0x63, 0x00, 0x00, 0x02, 0x66,
0x02, 0x63, 0x20, 0x00, 0x02, 0x36, 0x02, 0x66, 0x00, 0x00, 0x02, 0x36,
0x02, 0x60, 0x20, 0x00, 0x02, 0x06, 0x02, 0x63, 0x00, 0x00, 0x02, 0x06,
0x02, 0x60, 0x0c, 0x00, 0x00, 0x08, 0x03, 0x66, 0x66, 0x30, 0x0c, 0x00,
0x02, 0x06, 0x02, 0x60, 0x00, 0x00, 0x02, 0x03, 0x02, 0x66, 0x0c, 0x00,
0x00, 0x08, 0x06, 0x11, 0x11, 0x60, 0x0c, 0x00, 0x02, 0x66, 0x02, 0x30,
0x00, 0x00, 0x02, 0x00, 0x02, 0x66, 0x0c, 0x00, 0x00, 0x08, 0x06, 0x21,
0x21, 0x60, 0x0c, 0x00, 0x02, 0x66, 0x02, 0x00, 0x00, 0x00, 0x00, 0x06,
0x00, 0x36, 0x60, 0x00, 0x0a, 0x00, 0x00, 0x08, 0x06, 0x42, 0x42, 0x60,
0x0a, 0x00, 0x00, 0x06, 0x06, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
0x00, 0x06, 0x60, 0x00, 0x0a, 0x00, 0x00, 0x08, 0x06, 0x54, 0x45, 0x60,
0x0a, 0x00, 0x00, 0x06, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
0x00, 0x03, 0x66, 0x00, 0x0a, 0x00, 0x00, 0x08, 0x03, 0x66, 0x66, 0x30,
0x0a, 0x00, 0x00, 0x06, 0x66, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x66, 0x00, 0x1c, 0x00, 0x00, 0x06, 0x66, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x36, 0x60, 0x18, 0x00, 0x00, 0x08,
0x06, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x60,
0x0a, 0x00, 0x02, 0x36, 0x02, 0x63, 0x0a, 0x00, 0x00, 0x08, 0x06, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x66, 0x08, 0x00,
0x00, 0x08, 0x03, 0x61, 0x16, 0x30, 0x08, 0x00, 0x00, 0x08, 0x66, 0x30,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x66, 0x08, 0x00, 0x00, 0x08,
0x06, 0x11, 0x11, 0x60, 0x08, 0x00, 0x02, 0x66, 0x06, 0x00, 0x00, 0x00,
0x06, 0x00, 0x02, 0x36, 0x02, 0x60, 0x06, 0x00, 0x00, 0x08, 0x06, 0x11,
0x11, 0x60, 0x06, 0x00, 0x02, 0x06, 0x02, 0x63, 0x06, 0x00, 0x00, 0x00,
0x06, 0x00, 0x02, 0x06, 0x02, 0x60, 0x06, 0x00, 0x00, 0x08, 0x06, 0x11,
0x11, 0x60, 0x06, 0x00, 0x02, 0x06, 0x02, 0x60, 0x06, 0x00, 0x00, 0x00,
0x06, 0x00, 0x02, 0x03, 0x02, 0x66, 0x06, 0x00, 0x00, 0x08, 0x06, 0x11,
0x11, 0x60, 0x06, 0x00, 0x02, 0x66, 0x02, 0x30, 0x06, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x66, 0x06, 0x00, 0x00, 0x08, 0x06, 0x11, 0x11, 0x60,
0x06, 0x00, 0x02, 0x66, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18,
0x36, 0x60, 0x00, 0x00, 0x06, 0x11, 0x11, 0x60, 0x00, 0x00, 0x06, 0x63,
0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x06, 0x60, 0x00, 0x00,
0x06, 0x21, 0x21, 0x60, 0x00, 0x00, 0x06, 0x60, 0x08, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x18, 0x03, 0x66, 0x00, 0x00, 0x06, 0x12, 0x12, 0x60,
0x00, 0x00, 0x66, 0x30, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x14,
0x66, 0x00, 0x00, 0x06, 0x21, 0x21, 0x60, 0x00, 0x00, 0x66, 0x0a, 0x00,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x14, 0x36, 0x60, 0x00, 0x06, 0x22, 0x22,
0x60, 0x00, 0x06, 0x63, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x14,
0x06, 0x60, 0x00, 0x06, 0x24, 0x24, 0x60, 0x00, 0x06, 0x60, 0x0a, 0x00,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x14, 0x03, 0x66, 0x00, 0x06, 0x42, 0x42,
0x60, 0x00, 0x66, 0x30, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10,
0x66, 0x00, 0x06, 0x54, 0x45, 0x60, 0x00, 0x66, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x10, 0x36, 0x60, 0x03, 0x66, 0x66, 0x30, 0x06, 0x63,
0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x06, 0x02, 0x60, 0x08, 0x00,
0x02, 0x06, 0x02, 0x60, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x03,
0x02, 0x66, 0x08, 0x00, 0x02, 0x66, 0x02, 0x30, 0x0c, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x02, 0x66, 0x08, 0x00, 0x02, 0x66, 0x0e, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x0c, 0x36, 0x60, 0x00, 0x00, 0x06, 0x63, 0x0e, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x00, 0x0c, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60,
0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x0c, 0x03, 0x66, 0x00, 0x00,
0x66, 0x30, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x66, 0x00,
0x00, 0x66, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x36, 0x60,
0x06, 0x63, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x06, 0x60,
0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x03, 0x66,
0x66, 0x30, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x66, 0x02, 0x66,
0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x36, 0x02, 0x63, 0x12, 0x00,
0x00, 0x01};
unsigned int modal_warning_bmp_len = 830;
-327
View File
@@ -1,327 +0,0 @@
// converted by bmp_to_hex_cpp_arr.py at the firmware/tools dir
// fake transparent px should be the exact color rgb dec(41,24,22), then use true for the last arg when drawing bmp with the draw func
const unsigned char splash_bmp[] = {
0x42, 0x4d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x0e,
0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x0f, 0x00,
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x19, 0xf6, 0x00, 0x00, 0x14,
0xc9, 0x00, 0x00, 0x0c, 0x78, 0x00, 0x16, 0x18, 0x29, 0x00, 0xfd, 0xfd,
0xfd, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xe7, 0xe7, 0xe7, 0x00, 0xda, 0xda,
0xda, 0x00, 0xcd, 0xcd, 0xcd, 0x00, 0xc7, 0xc7, 0xc7, 0x00, 0xba, 0xba,
0xba, 0x00, 0xad, 0xad, 0xad, 0x00, 0x96, 0x96, 0x96, 0x00, 0x5c, 0x5c,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0x00, 0x08,
0x33, 0x44, 0x44, 0x47, 0x0a, 0x33, 0x00, 0x06, 0xd5, 0x44, 0x7d, 0x00,
0x0a, 0x33, 0x00, 0x0a, 0x44, 0x44, 0x48, 0x33, 0x3a, 0x00, 0x06, 0x44,
0x02, 0xd3, 0x12, 0x33, 0x00, 0x08, 0xa4, 0x44, 0x45, 0x9d, 0x08, 0x33,
0x00, 0x08, 0xc4, 0x44, 0x45, 0xc3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x44,
0x44, 0x6d, 0x16, 0x33, 0x00, 0x08, 0x34, 0x44, 0x44, 0x6d, 0x08, 0x33,
0x02, 0xd5, 0x1a, 0x44, 0x00, 0x0c, 0x45, 0xc3, 0x33, 0x44, 0x44, 0x47,
0x0a, 0x33, 0x00, 0x06, 0xd5, 0x44, 0x7d, 0x00, 0x0a, 0x33, 0x00, 0x08,
0x44, 0x44, 0x48, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x33, 0x49, 0x99, 0x95,
0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a, 0xd4, 0x46, 0x89, 0x98, 0xb3, 0x00,
0x08, 0x33, 0x00, 0x12, 0x49, 0x99, 0x94, 0x33, 0x3d, 0x79, 0x99, 0x99,
0x73, 0x00, 0x10, 0x33, 0x00, 0x0a, 0x3d, 0x47, 0x99, 0x95, 0xa3, 0x00,
0x08, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c,
0x06, 0x33, 0x00, 0x06, 0xb4, 0x56, 0x89, 0x00, 0x18, 0x99, 0x00, 0x0e,
0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a,
0xd4, 0x46, 0x89, 0x98, 0xb3, 0x00, 0x08, 0x33, 0x00, 0x08, 0x49, 0x99,
0x94, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00,
0x06, 0x33, 0x02, 0x55, 0x06, 0x99, 0x02, 0x9b, 0x08, 0x33, 0x00, 0x12,
0x49, 0x99, 0x94, 0x33, 0x33, 0xb9, 0x99, 0x99, 0x8d, 0x00, 0x10, 0x33,
0x00, 0x0a, 0x37, 0x69, 0x99, 0x74, 0xd3, 0x00, 0x08, 0x33, 0x00, 0x08,
0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c,
0x16, 0x33, 0x00, 0x10, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x33, 0x3a, 0x47,
0x1c, 0x99, 0x00, 0x0e, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x00,
0x06, 0x33, 0x02, 0x55, 0x06, 0x99, 0x02, 0x9b, 0x08, 0x33, 0x00, 0x08,
0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95,
0xd3, 0x33, 0x33, 0x3a, 0x48, 0x00, 0x06, 0x99, 0x02, 0x98, 0x02, 0xd3,
0x06, 0x33, 0x00, 0x12, 0x49, 0x99, 0x94, 0x33, 0x33, 0xd7, 0x99, 0x99,
0x98, 0x00, 0x10, 0x33, 0x00, 0x08, 0xd4, 0x89, 0x99, 0x5a, 0x0a, 0x33,
0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99,
0x99, 0x7c, 0x16, 0x33, 0x00, 0x10, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x33,
0xb4, 0x79, 0x1c, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95,
0xd3, 0x33, 0x33, 0x3a, 0x48, 0x00, 0x06, 0x99, 0x02, 0x98, 0x02, 0xd3,
0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x12,
0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x33, 0xd4, 0x79, 0x00, 0x08, 0x99,
0x02, 0x73, 0x06, 0x33, 0x00, 0x0c, 0x49, 0x99, 0x94, 0x33, 0x33, 0x3b,
0x06, 0x99, 0x02, 0xc3, 0x0e, 0x33, 0x00, 0x08, 0x56, 0x99, 0x97, 0x4d,
0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
0x33, 0x3d, 0x47, 0x00, 0x1e, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49,
0x99, 0x95, 0xd3, 0x33, 0x33, 0xd4, 0x79, 0x00, 0x08, 0x99, 0x02, 0x73,
0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x10,
0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x33, 0xa5, 0x0a, 0x99, 0x02, 0x8d,
0x06, 0x33, 0x00, 0x14, 0x49, 0x99, 0x94, 0x33, 0x33, 0x3d, 0x79, 0x99,
0x99, 0x73, 0x0c, 0x33, 0x00, 0x0a, 0x3c, 0x48, 0x99, 0x95, 0xa3, 0x00,
0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x97, 0xa3, 0x10, 0x33, 0x00, 0x08,
0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
0x33, 0x37, 0x69, 0x00, 0x1e, 0x99, 0x00, 0x14, 0x97, 0xa3, 0x33, 0x49,
0x99, 0x95, 0xd3, 0x33, 0x33, 0xa5, 0x0a, 0x99, 0x02, 0x8d, 0x06, 0x33,
0x00, 0x08, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x1c, 0x33, 0x49,
0x99, 0x95, 0xd3, 0x33, 0x3d, 0x47, 0x99, 0x97, 0x89, 0x99, 0x99, 0x97,
0x06, 0x33, 0x00, 0x06, 0x49, 0x99, 0x94, 0x00, 0x06, 0x33, 0x00, 0x08,
0xb9, 0x99, 0x99, 0x9d, 0x0c, 0x33, 0x00, 0x0a, 0x34, 0x69, 0x99, 0x74,
0xd3, 0x00, 0x0a, 0x33, 0x00, 0x08, 0xc7, 0x99, 0x98, 0xa3, 0x10, 0x33,
0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99,
0x99, 0x7c, 0x33, 0x34, 0x89, 0x99, 0x64, 0x00, 0x1c, 0x44, 0x00, 0x1e,
0xa3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3d, 0x47, 0x99, 0x97, 0x89,
0x99, 0x99, 0x97, 0x00, 0x06, 0x33, 0x00, 0x08, 0x49, 0x99, 0x94, 0x33,
0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3c, 0x59,
0x99, 0x95, 0xbc, 0x99, 0x99, 0x98, 0xd3, 0x33, 0x33, 0x49, 0x99, 0x94,
0x06, 0x33, 0x02, 0xd7, 0x06, 0x99, 0x02, 0x74, 0x0c, 0x44, 0x00, 0x06,
0x99, 0x99, 0x4b, 0x00, 0x0c, 0x33, 0x00, 0x08, 0xb7, 0x99, 0x99, 0xa3,
0x10, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x16, 0x33, 0x00, 0x12,
0x34, 0x99, 0x99, 0x7c, 0x33, 0xd5, 0x99, 0x99, 0x6d, 0x00, 0x20, 0x33,
0x00, 0x28, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x3c, 0x59, 0x99, 0x95, 0xbc,
0x99, 0x99, 0x98, 0xd3, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00,
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x34, 0x79, 0x99, 0x84,
0xdd, 0x89, 0x99, 0x99, 0x83, 0x33, 0x33, 0x49, 0x99, 0x94, 0x06, 0x33,
0x02, 0x3b, 0x16, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0x33, 0x00, 0x0a,
0x3d, 0x47, 0x99, 0x99, 0x9d, 0x00, 0x10, 0x33, 0x00, 0x08, 0x34, 0x99,
0x99, 0x9d, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6,
0x99, 0x99, 0x6d, 0x00, 0x20, 0x33, 0x00, 0x28, 0x49, 0x99, 0x95, 0xd3,
0x33, 0x34, 0x79, 0x99, 0x84, 0xdd, 0x89, 0x99, 0x99, 0x83, 0x33, 0x33,
0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95,
0xd3, 0x33, 0xc4, 0x99, 0x99, 0x67, 0x33, 0x79, 0x99, 0x99, 0x8d, 0x33,
0x33, 0x49, 0x99, 0x94, 0x06, 0x33, 0x02, 0x3d, 0x02, 0x79, 0x14, 0x99,
0x02, 0x94, 0x02, 0xc3, 0x0a, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x99,
0x98, 0x00, 0x10, 0x33, 0x02, 0x34, 0x06, 0x99, 0x02, 0x74, 0x16, 0x44,
0x00, 0x10, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x9d, 0x20, 0x33,
0x00, 0x28, 0x49, 0x99, 0x95, 0xd3, 0x33, 0xc4, 0x99, 0x99, 0x67, 0x33,
0x79, 0x99, 0x99, 0x8d, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00,
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x57, 0x99, 0x99, 0x4d,
0x33, 0xd8, 0x99, 0x99, 0x98, 0x33, 0x33, 0x49, 0x99, 0x94, 0x08, 0x33,
0x02, 0xc9, 0x14, 0x99, 0x02, 0x74, 0x0c, 0x33, 0x02, 0x84, 0x02, 0x89,
0x06, 0x99, 0x02, 0xa3, 0x0e, 0x33, 0x02, 0x34, 0x22, 0x99, 0x00, 0x06,
0x7c, 0x33, 0xd6, 0x00, 0x06, 0x99, 0x02, 0x64, 0x18, 0x44, 0x00, 0x2e,
0x45, 0xc3, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x33, 0x57, 0x99, 0x99, 0x4d,
0x33, 0xd8, 0x99, 0x99, 0x98, 0x33, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
0x00, 0x00, 0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x3d, 0x48, 0x99,
0x97, 0x43, 0x33, 0x37, 0x99, 0x99, 0x97, 0xd3, 0x33, 0x49, 0x99, 0x94,
0x08, 0x33, 0x02, 0x37, 0x14, 0x99, 0x02, 0x4c, 0x0a, 0x33, 0x02, 0x3b,
0x02, 0x48, 0x08, 0x99, 0x02, 0x9b, 0x0e, 0x33, 0x02, 0x34, 0x22, 0x99,
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xa3,
0x33, 0x49, 0x99, 0x95, 0xd3, 0x3d, 0x48, 0x99, 0x97, 0x43, 0x33, 0x37,
0x99, 0x99, 0x97, 0xd3, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00,
0x00, 0x28, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x35, 0x69, 0x99, 0x95, 0xc3,
0x33, 0x3c, 0x89, 0x99, 0x99, 0xb3, 0x33, 0x49, 0x99, 0x94, 0x08, 0x33,
0x02, 0x3c, 0x12, 0x99, 0x02, 0x97, 0x02, 0x43, 0x0a, 0x33, 0x02, 0xd4,
0x02, 0x79, 0x0a, 0x99, 0x02, 0xd3, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x2e, 0x97, 0xa3,
0x33, 0x49, 0x99, 0x95, 0xd3, 0x35, 0x69, 0x99, 0x95, 0xc3, 0x33, 0x3c,
0x89, 0x99, 0x99, 0xb3, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00,
0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0xd3, 0xd4, 0x89, 0x99, 0x74, 0x00,
0x06, 0x33, 0x00, 0x10, 0x79, 0x99, 0x99, 0x7d, 0x33, 0x49, 0x99, 0x94,
0x0a, 0x33, 0x00, 0x16, 0x79, 0x99, 0x99, 0x64, 0x44, 0x44, 0x89, 0x99,
0x99, 0x94, 0xc3, 0x00, 0x08, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x98,
0x59, 0x00, 0x06, 0x99, 0x02, 0x8d, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x16, 0x97, 0xa3,
0x33, 0x49, 0x99, 0x95, 0xd3, 0xd4, 0x89, 0x99, 0x74, 0x00, 0x06, 0x33,
0x00, 0x12, 0x79, 0x99, 0x99, 0x7d, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0xd3, 0x76, 0x99, 0x99,
0x6a, 0x00, 0x06, 0x33, 0x00, 0x10, 0xa9, 0x99, 0x99, 0x9b, 0x33, 0x49,
0x99, 0x94, 0x0a, 0x33, 0x00, 0x14, 0xc9, 0x99, 0x99, 0x9c, 0x33, 0x33,
0x3b, 0x99, 0x99, 0x74, 0x0a, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x95,
0x7d, 0x00, 0x06, 0x99, 0x02, 0x9a, 0x0c, 0x33, 0x02, 0x34, 0x22, 0x99,
0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00, 0x20, 0x99, 0x00, 0x16, 0x97, 0xa3,
0x33, 0x49, 0x99, 0x95, 0xd3, 0x76, 0x99, 0x99, 0x6a, 0x00, 0x06, 0x33,
0x00, 0x12, 0xa9, 0x99, 0x99, 0x9b, 0x33, 0x49, 0x99, 0x94, 0x33, 0x00,
0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x95, 0x3d, 0x48, 0x99, 0x98,
0x4d, 0x00, 0x06, 0x33, 0x00, 0x10, 0xd7, 0x99, 0x99, 0x97, 0xd3, 0x49,
0x99, 0x94, 0x0a, 0x33, 0x00, 0x14, 0x37, 0x99, 0x99, 0x97, 0x33, 0x33,
0xc4, 0x89, 0x99, 0x4c, 0x0a, 0x33, 0x00, 0x0c, 0x84, 0x89, 0x99, 0x64,
0x33, 0xd9, 0x06, 0x99, 0x02, 0xa3, 0x0a, 0x33, 0x00, 0x08, 0x34, 0x99,
0x99, 0x64, 0x16, 0x44, 0x06, 0x99, 0x00, 0x06, 0x7c, 0x33, 0xd6, 0x00,
0x20, 0x99, 0x00, 0x16, 0x97, 0xa3, 0x33, 0x49, 0x99, 0x95, 0x3d, 0x48,
0x99, 0x98, 0x4d, 0x00, 0x06, 0x33, 0x00, 0x12, 0xd7, 0x99, 0x99, 0x97,
0xd3, 0x49, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49,
0x99, 0x96, 0x3b, 0x69, 0x99, 0x96, 0x53, 0x00, 0x06, 0x33, 0x02, 0x38,
0x06, 0x99, 0x00, 0x08, 0xc3, 0x49, 0x99, 0x94, 0x0a, 0x33, 0x02, 0x3c,
0x06, 0x99, 0x00, 0x0c, 0xb3, 0x33, 0x46, 0x99, 0x96, 0x43, 0x08, 0x33,
0x00, 0x0e, 0x3b, 0x48, 0x99, 0x97, 0x4d, 0x33, 0x3d, 0x00, 0x06, 0x99,
0x02, 0x9c, 0x0a, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33,
0x00, 0x12, 0x39, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x54, 0x00,
0x1c, 0x44, 0x00, 0x14, 0xa3, 0x33, 0x49, 0x99, 0x96, 0x3b, 0x69, 0x99,
0x96, 0x53, 0x06, 0x33, 0x02, 0x38, 0x06, 0x99, 0x00, 0x0a, 0xc3, 0x49,
0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12, 0x33, 0x49, 0x99, 0x98,
0xd5, 0x79, 0x99, 0x94, 0xd3, 0x00, 0x06, 0x33, 0x00, 0x10, 0x3d, 0x89,
0x99, 0x99, 0x73, 0x49, 0x99, 0x94, 0x0c, 0x33, 0x00, 0x12, 0x79, 0x99,
0x99, 0x8d, 0x3a, 0x59, 0x99, 0x84, 0xd3, 0x00, 0x08, 0x33, 0x00, 0x10,
0xd4, 0x79, 0x99, 0x84, 0xb3, 0x33, 0x33, 0xb9, 0x06, 0x99, 0x02, 0xd3,
0x08, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x12,
0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6, 0x99, 0x99, 0x5d, 0x00, 0x20, 0x33,
0x00, 0x10, 0x49, 0x99, 0x98, 0xd5, 0x79, 0x99, 0x94, 0xd3, 0x06, 0x33,
0x00, 0x12, 0x3d, 0x89, 0x99, 0x99, 0x73, 0x49, 0x99, 0x94, 0x33, 0x00,
0x00, 0x00, 0x00, 0x10, 0x33, 0x49, 0x99, 0x99, 0xa6, 0x99, 0x99, 0x74,
0x0a, 0x33, 0x00, 0x0e, 0x79, 0x99, 0x99, 0x9c, 0x59, 0x99, 0x94, 0x00,
0x0c, 0x33, 0x00, 0x10, 0xc9, 0x99, 0x99, 0x9a, 0xd4, 0x79, 0x99, 0x65,
0x08, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x98, 0x48, 0x00, 0x06, 0x33,
0x02, 0x3a, 0x06, 0x99, 0x02, 0x83, 0x08, 0x33, 0x00, 0x08, 0x34, 0x99,
0x99, 0x6d, 0x16, 0x33, 0x00, 0x12, 0x34, 0x99, 0x99, 0x7c, 0x33, 0xd6,
0x99, 0x99, 0x93, 0x00, 0x20, 0x33, 0x00, 0x0e, 0x49, 0x99, 0x99, 0xa6,
0x99, 0x99, 0x74, 0x00, 0x0a, 0x33, 0x00, 0x10, 0x79, 0x99, 0x99, 0x9c,
0x59, 0x99, 0x94, 0x33, 0x00, 0x00, 0x00, 0x10, 0x33, 0x49, 0x99, 0x99,
0x98, 0x99, 0x99, 0x5c, 0x0a, 0x33, 0x02, 0xd8, 0x06, 0x99, 0x00, 0x06,
0x79, 0x99, 0x84, 0x00, 0x0c, 0x33, 0x02, 0x37, 0x06, 0x99, 0x00, 0x08,
0x86, 0x99, 0x98, 0x4d, 0x08, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x95,
0x53, 0x00, 0x08, 0x33, 0x00, 0x08, 0x89, 0x99, 0x99, 0x9a, 0x08, 0x33,
0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x0c, 0x34, 0x99,
0x99, 0x7c, 0x33, 0x36, 0x06, 0x99, 0x02, 0x54, 0x18, 0x44, 0x00, 0x14,
0x45, 0xc3, 0x33, 0x49, 0x99, 0x99, 0x98, 0x99, 0x99, 0x5c, 0x0a, 0x33,
0x02, 0xd8, 0x06, 0x99, 0x00, 0x08, 0x79, 0x99, 0x84, 0x33, 0x00, 0x00,
0x02, 0x33, 0x02, 0x59, 0x08, 0x99, 0x02, 0x97, 0x02, 0x4d, 0x0a, 0x33,
0x02, 0x36, 0x0a, 0x99, 0x02, 0x75, 0x0c, 0x33, 0x02, 0x3c, 0x0a, 0x99,
0x02, 0x96, 0x02, 0x53, 0x08, 0x33, 0x00, 0x0a, 0x84, 0x89, 0x99, 0x64,
0xd3, 0x00, 0x08, 0x33, 0x02, 0xd9, 0x06, 0x99, 0x02, 0xb3, 0x06, 0x33,
0x00, 0x08, 0x34, 0x99, 0x99, 0x6d, 0x16, 0x33, 0x00, 0x0c, 0x34, 0x99,
0x99, 0x7c, 0x33, 0x36, 0x20, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0x59,
0x08, 0x99, 0x02, 0x97, 0x02, 0x4d, 0x0a, 0x33, 0x02, 0x36, 0x0a, 0x99,
0x02, 0x75, 0x02, 0x33, 0x00, 0x00, 0x02, 0x33, 0x02, 0xa8, 0x08, 0x99,
0x02, 0x95, 0x02, 0xa3, 0x0a, 0x33, 0x02, 0x3c, 0x0a, 0x99, 0x02, 0x5b,
0x0e, 0x33, 0x02, 0x89, 0x08, 0x99, 0x02, 0x84, 0x02, 0xd3, 0x06, 0x33,
0x00, 0x0a, 0x3b, 0x48, 0x99, 0x97, 0x4c, 0x00, 0x0a, 0x33, 0x02, 0x3d,
0x06, 0x99, 0x02, 0x9d, 0x06, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x6d,
0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c, 0x33, 0x3d, 0x89, 0x00,
0x1e, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0xa8, 0x08, 0x99, 0x02, 0x95,
0x02, 0xa3, 0x0a, 0x33, 0x02, 0x3c, 0x0a, 0x99, 0x02, 0x5b, 0x02, 0x33,
0x00, 0x00, 0x02, 0x33, 0x02, 0xd7, 0x08, 0x99, 0x02, 0x64, 0x0e, 0x33,
0x02, 0x79, 0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd8,
0x06, 0x99, 0x02, 0x98, 0x02, 0x48, 0x08, 0x33, 0x00, 0x0a, 0xd4, 0x79,
0x99, 0x84, 0xb3, 0x00, 0x0c, 0x33, 0x00, 0x16, 0xb9, 0x99, 0x99, 0x98,
0xd3, 0x33, 0x33, 0x34, 0x99, 0x99, 0x6d, 0x00, 0x16, 0x33, 0x00, 0x0c,
0x34, 0x99, 0x99, 0x7c, 0x33, 0x33, 0x20, 0x99, 0x00, 0x08, 0x97, 0xa3,
0x33, 0xd7, 0x08, 0x99, 0x02, 0x64, 0x0e, 0x33, 0x02, 0x79, 0x06, 0x99,
0x00, 0x06, 0x96, 0x4d, 0x33, 0x00, 0x00, 0x00, 0x02, 0x33, 0x02, 0x3c,
0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd9, 0x06, 0x99,
0x02, 0x74, 0x02, 0xc3, 0x0e, 0x33, 0x02, 0x3d, 0x06, 0x99, 0x02, 0x85,
0x02, 0x53, 0x06, 0x33, 0x00, 0x0a, 0x3d, 0x46, 0x99, 0x99, 0x57, 0x00,
0x0e, 0x33, 0x02, 0x39, 0x06, 0x99, 0x00, 0x0e, 0xa3, 0x33, 0x33, 0x34,
0x99, 0x99, 0x6d, 0x00, 0x16, 0x33, 0x00, 0x0e, 0x34, 0x99, 0x99, 0x7c,
0x33, 0x33, 0x3a, 0x00, 0x1e, 0x99, 0x00, 0x08, 0x97, 0xa3, 0x33, 0x3c,
0x06, 0x99, 0x02, 0x96, 0x02, 0x4d, 0x0e, 0x33, 0x02, 0xd9, 0x06, 0x99,
0x00, 0x06, 0x74, 0xc3, 0x33, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x33, 0x33,
0xc8, 0x99, 0x96, 0x44, 0xd3, 0x00, 0x0e, 0x33, 0x00, 0x0a, 0x3d, 0x79,
0x99, 0x76, 0x4b, 0x00, 0x12, 0x33, 0x00, 0x0a, 0xc7, 0x99, 0x96, 0x45,
0xd3, 0x00, 0x06, 0x33, 0x00, 0x0a, 0x35, 0x59, 0x99, 0x96, 0x43, 0x00,
0x10, 0x33, 0x00, 0x14, 0x89, 0x99, 0x99, 0x9a, 0x33, 0x33, 0x34, 0x99,
0x99, 0x6d, 0x16, 0x33, 0x00, 0x08, 0x34, 0x99, 0x99, 0x7c, 0x06, 0x33,
0x02, 0xa6, 0x1c, 0x99, 0x00, 0x12, 0x97, 0xa3, 0x33, 0x33, 0xc8, 0x99,
0x96, 0x44, 0xd3, 0x00, 0x0e, 0x33, 0x00, 0x0e, 0x3d, 0x79, 0x99, 0x76,
0x4b, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x33, 0x33, 0x3d, 0x84,
0x44, 0xc3, 0x12, 0x33, 0x00, 0x08, 0xdc, 0x44, 0x4a, 0xd3, 0x12, 0x33,
0x00, 0x08, 0x3d, 0xa4, 0x44, 0xd3, 0x08, 0x33, 0x02, 0xc8, 0x06, 0x44,
0x02, 0xd3, 0x10, 0x33, 0x02, 0xd4, 0x06, 0x44, 0x00, 0x0c, 0xa3, 0x33,
0x38, 0x44, 0x44, 0x4d, 0x16, 0x33, 0x00, 0x08, 0x38, 0x44, 0x44, 0x4c,
0x06, 0x33, 0x02, 0x3d, 0x02, 0xc4, 0x1c, 0x44, 0x00, 0x0e, 0xa3, 0x33,
0x33, 0x3d, 0x84, 0x44, 0xc3, 0x00, 0x12, 0x33, 0x00, 0x0c, 0xdc, 0x44,
0x4a, 0xd3, 0x33, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
0x00, 0x00, 0x00, 0x1e, 0x33, 0x20, 0x00, 0x23, 0x30, 0x00, 0x13, 0x31,
0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x26,
0x13, 0x31, 0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x00, 0x00, 0x13, 0x33,
0x00, 0x00, 0x13, 0x32, 0x00, 0x00, 0x23, 0x00, 0x24, 0x33, 0x00, 0x06,
0x32, 0x00, 0x02, 0x00, 0x08, 0x33, 0x02, 0x32, 0x06, 0x00, 0x00, 0x30,
0x01, 0x33, 0x31, 0x00, 0x02, 0x33, 0x00, 0x01, 0x33, 0x33, 0x32, 0x00,
0x02, 0x33, 0x33, 0x30, 0x00, 0x13, 0x32, 0x00, 0x02, 0x33, 0x00, 0x01,
0x08, 0x33, 0x00, 0x10, 0x30, 0x00, 0x13, 0x31, 0x00, 0x02, 0x33, 0x30,
0x08, 0x00, 0x00, 0x10, 0x23, 0x30, 0x00, 0x13, 0x31, 0x00, 0x02, 0x33,
0x00, 0x00, 0x00, 0x20, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x10, 0x10, 0x06, 0x00, 0x00, 0x26,
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x03, 0x33,
0x01, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x00, 0x24, 0x33, 0x00, 0x06,
0x32, 0x01, 0x11, 0x00, 0x08, 0x33, 0x00, 0x38, 0x10, 0x10, 0x00, 0x11,
0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x33, 0x32, 0x01,
0x11, 0x33, 0x33, 0x30, 0x11, 0x03, 0x32, 0x01, 0x11, 0x33, 0x01, 0x10,
0x08, 0x33, 0x00, 0x12, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00,
0x10, 0x00, 0x06, 0x00, 0x00, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31, 0x11,
0x02, 0x33, 0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11,
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00,
0x06, 0x33, 0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01,
0x11, 0x13, 0x33, 0x01, 0x10, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33,
0x00, 0x06, 0x32, 0x01, 0x11, 0x00, 0x08, 0x33, 0x00, 0x38, 0x11, 0x10,
0x23, 0x31, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x33,
0x32, 0x01, 0x11, 0x33, 0x33, 0x30, 0x11, 0x03, 0x32, 0x01, 0x11, 0x33,
0x01, 0x10, 0x08, 0x33, 0x00, 0x12, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02,
0x33, 0x01, 0x10, 0x00, 0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31,
0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x23,
0x30, 0x11, 0x03, 0x31, 0x11, 0x12, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10,
0x23, 0x00, 0x06, 0x33, 0x00, 0x28, 0x31, 0x11, 0x12, 0x33, 0x01, 0x00,
0x33, 0x01, 0x11, 0x11, 0x00, 0x01, 0x12, 0x33, 0x32, 0x01, 0x11, 0x11,
0x00, 0x23, 0x20, 0x33, 0x00, 0x06, 0x32, 0x01, 0x12, 0x00, 0x08, 0x33,
0x00, 0x38, 0x11, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31, 0x11, 0x12, 0x33,
0x01, 0x00, 0x33, 0x33, 0x32, 0x01, 0x11, 0x33, 0x33, 0x30, 0x11, 0x13,
0x32, 0x01, 0x11, 0x33, 0x01, 0x11, 0x08, 0x33, 0x00, 0x12, 0x30, 0x11,
0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x00, 0x08, 0x33, 0x00, 0x0e,
0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x22,
0x33, 0x20, 0x11, 0x11, 0x00, 0x11, 0x03, 0x31, 0x11, 0x11, 0x00, 0x01,
0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33, 0x00, 0x10, 0x31, 0x11,
0x11, 0x00, 0x01, 0x13, 0x33, 0x01, 0x08, 0x11, 0x00, 0x10, 0x12, 0x33,
0x32, 0x01, 0x11, 0x11, 0x10, 0x23, 0x20, 0x33, 0x00, 0x60, 0x32, 0x01,
0x11, 0x10, 0x00, 0x03, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11, 0x03, 0x31,
0x11, 0x12, 0x22, 0x01, 0x02, 0x33, 0x33, 0x32, 0x01, 0x11, 0x33, 0x33,
0x30, 0x11, 0x12, 0x21, 0x01, 0x11, 0x33, 0x01, 0x11, 0x22, 0x22, 0x23,
0x33, 0x30, 0x11, 0x12, 0x21, 0x11, 0x02, 0x33, 0x01, 0x10, 0x08, 0x33,
0x00, 0x0e, 0x30, 0x11, 0x12, 0x21, 0x10, 0x13, 0x33, 0x00, 0x00, 0x00,
0x00, 0x22, 0x33, 0x20, 0x11, 0x00, 0x11, 0x11, 0x03, 0x31, 0x11, 0x00,
0x01, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33, 0x00, 0x28,
0x31, 0x11, 0x00, 0x01, 0x11, 0x13, 0x33, 0x01, 0x11, 0x00, 0x01, 0x11,
0x12, 0x33, 0x32, 0x01, 0x11, 0x00, 0x00, 0x23, 0x20, 0x33, 0x00, 0x60,
0x32, 0x01, 0x10, 0x01, 0x11, 0x12, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11,
0x03, 0x31, 0x11, 0x10, 0x10, 0x11, 0x13, 0x33, 0x33, 0x32, 0x01, 0x11,
0x33, 0x33, 0x30, 0x11, 0x10, 0x10, 0x11, 0x11, 0x33, 0x01, 0x11, 0x01,
0x00, 0x01, 0x23, 0x30, 0x11, 0x00, 0x10, 0x11, 0x02, 0x33, 0x01, 0x10,
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x00, 0x10, 0x11, 0x23, 0x33, 0x00,
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x31, 0x11, 0x03, 0x31,
0x11, 0x02, 0x33, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33,
0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x11, 0x10, 0x33, 0x01, 0x11, 0x03,
0x33, 0x11, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33, 0x00, 0x60,
0x32, 0x01, 0x11, 0x33, 0x11, 0x10, 0x33, 0x11, 0x10, 0x23, 0x30, 0x11,
0x03, 0x31, 0x11, 0x01, 0x22, 0x11, 0x12, 0x33, 0x33, 0x32, 0x01, 0x11,
0x33, 0x33, 0x30, 0x11, 0x02, 0x22, 0x11, 0x11, 0x33, 0x01, 0x10, 0x22,
0x21, 0x11, 0x13, 0x30, 0x11, 0x02, 0x21, 0x11, 0x02, 0x33, 0x01, 0x10,
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x02, 0x21, 0x11, 0x23, 0x33, 0x00,
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x11, 0x10, 0x23, 0x00, 0x06, 0x33,
0x00, 0x24, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x13,
0x33, 0x01, 0x11, 0x13, 0x32, 0x01, 0x11, 0x23, 0x24, 0x33, 0x00, 0x60,
0x32, 0x01, 0x11, 0x33, 0x01, 0x10, 0x33, 0x11, 0x11, 0x23, 0x30, 0x11,
0x03, 0x31, 0x11, 0x12, 0x33, 0x11, 0x10, 0x33, 0x33, 0x32, 0x01, 0x11,
0x33, 0x33, 0x30, 0x11, 0x13, 0x32, 0x11, 0x11, 0x33, 0x01, 0x11, 0x33,
0x21, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10,
0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00,
0x00, 0x00, 0x00, 0x22, 0x33, 0x20, 0x11, 0x13, 0x30, 0x11, 0x03, 0x31,
0x11, 0x12, 0x33, 0x01, 0x00, 0x33, 0x11, 0x11, 0x23, 0x00, 0x06, 0x33,
0x00, 0x2c, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01, 0x11, 0x11,
0x00, 0x01, 0x10, 0x13, 0x32, 0x01, 0x11, 0x11, 0x00, 0x00, 0x01, 0x23,
0x1c, 0x33, 0x00, 0x60, 0x32, 0x01, 0x12, 0x33, 0x01, 0x00, 0x33, 0x11,
0x11, 0x22, 0x20, 0x11, 0x03, 0x31, 0x11, 0x12, 0x22, 0x01, 0x10, 0x33,
0x33, 0x32, 0x01, 0x12, 0x33, 0x33, 0x30, 0x11, 0x12, 0x21, 0x01, 0x11,
0x33, 0x01, 0x11, 0x22, 0x10, 0x11, 0x13, 0x30, 0x11, 0x12, 0x21, 0x11,
0x02, 0x33, 0x01, 0x11, 0x08, 0x33, 0x00, 0x0e, 0x30, 0x11, 0x03, 0x31,
0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x38, 0x33, 0x20, 0x11, 0x13,
0x30, 0x11, 0x03, 0x32, 0x11, 0x11, 0x00, 0x01, 0x02, 0x33, 0x21, 0x11,
0x10, 0x00, 0x00, 0x13, 0x31, 0x11, 0x02, 0x33, 0x01, 0x10, 0x33, 0x01,
0x08, 0x11, 0x00, 0x08, 0x12, 0x33, 0x33, 0x21, 0x08, 0x11, 0x02, 0x10,
0x02, 0x23, 0x1c, 0x33, 0x00, 0x0e, 0x32, 0x01, 0x11, 0x10, 0x01, 0x02,
0x33, 0x00, 0x06, 0x11, 0x00, 0x62, 0x01, 0x10, 0x03, 0x31, 0x11, 0x11,
0x10, 0x11, 0x00, 0x33, 0x10, 0x00, 0x01, 0x11, 0x10, 0x13, 0x30, 0x11,
0x11, 0x10, 0x11, 0x01, 0x33, 0x01, 0x11, 0x11, 0x01, 0x10, 0x13, 0x30,
0x11, 0x11, 0x00, 0x10, 0x02, 0x33, 0x01, 0x11, 0x10, 0x00, 0x00, 0x23,
0x30, 0x11, 0x03, 0x31, 0x11, 0x02, 0x33, 0x00, 0x00, 0x00, 0x00, 0x12,
0x33, 0x20, 0x00, 0x13, 0x31, 0x00, 0x03, 0x33, 0x20, 0x00, 0x06, 0x00,
0x00, 0x06, 0x13, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x12, 0x03, 0x32,
0x00, 0x02, 0x33, 0x10, 0x00, 0x33, 0x10, 0x00, 0x08, 0x00, 0x00, 0x08,
0x02, 0x33, 0x33, 0x30, 0x0a, 0x00, 0x02, 0x23, 0x1c, 0x33, 0x02, 0x32,
0x08, 0x00, 0x00, 0x06, 0x03, 0x33, 0x32, 0x00, 0x06, 0x00, 0x00, 0x06,
0x01, 0x33, 0x32, 0x00, 0x08, 0x00, 0x00, 0x06, 0x13, 0x33, 0x20, 0x00,
0x08, 0x00, 0x00, 0x06, 0x03, 0x33, 0x10, 0x00, 0x06, 0x00, 0x00, 0x06,
0x23, 0x33, 0x10, 0x00, 0x06, 0x00, 0x00, 0x06, 0x02, 0x33, 0x33, 0x00,
0x08, 0x00, 0x00, 0x06, 0x23, 0x33, 0x30, 0x00, 0x08, 0x00, 0x00, 0x10,
0x23, 0x31, 0x00, 0x03, 0x32, 0x00, 0x02, 0x33, 0x00, 0x00, 0xe6, 0x33,
0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33, 0x00, 0x00, 0xe6, 0x33,
0x00, 0x01};
unsigned int splash_new__new_t_len = 3854;
-104
View File
@@ -1,104 +0,0 @@
/*
* 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.
*/
#include "de_bruijn.hpp"
/* How this works:
* B(2,4) means:
* Alphabet size = 2 (binary)
* Code length = 4
* The length of the bitstream is (2 ^ 4) + (4 - 1) = 19 bits
* The primitive polynomials come from the de_bruijn_polys[] array (one for each code length)
* The shift register is init with 1 and shifted left each step
* The polynomial is kept on the right, and used as a AND mask applied on the corresponding shift register bits
* The resulting bits are XORed together to produce the new bit pushed in the shift register
*
* 0001 (init)
* AND 1001 (polynomial)
* 0001 XOR'd -> 1
*
* 00011 (shift left)
* AND 1001
* 0001 XOR'd -> 1
*
* 000111 (shift left)
* AND 1001
* 0001 XOR'd -> 1
*
* 0001111 (shift left)
* AND 1001
* 1001 XOR'd -> 0
*
* 00011110 (shift left)
* AND 1001
* 1000 XOR'd -> 1
* ...
* After 16 steps: (0+) 000111101011001000
* Each of the 16 possible values appears in the sequence:
* -0000-111101011001000 0
* 0-0001-11101011001000 1
* 0000111101011-0010-00 2
* 00-0011-1101011001000 3
* 00001111010110-0100-0 4
* 00001111-0101-1001000 5
* 0000111101-0110-01000 6
* 000-0111-101011001000 7
* 000011110101100-1000- 8
* 000011110101-1001-000 9
* 0000111-1010-11001000 10
* 000011110-1011-001000 11
* 00001111010-1100-1000 12
* 000011-1101-011001000 13
* 00001-1110-1011001000 14
* 0000-1111-01011001000 15
*/
size_t de_bruijn::init(const uint32_t n) {
// Cap
if ((n < 3) || (n > 16))
length = 3;
else
length = n;
poly = de_bruijn_polys[length - 3];
shift_register = 1;
return (1U << length) + (length - 1);
}
uint32_t de_bruijn::compute(const uint32_t steps) {
uint32_t step, bits, masked;
uint8_t new_bit;
for (step = 0; step < steps; step++) {
masked = shift_register & poly;
new_bit = 0;
for (bits = 0; bits < length; bits++) {
new_bit ^= (masked & 1);
masked >>= 1;
}
shift_register <<= 1;
shift_register |= new_bit;
}
return shift_register;
}
-57
View File
@@ -1,57 +0,0 @@
/*
* 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.
*/
#include <string>
#include <cstdint>
#ifndef __DE_BRUIJN_H__
#define __DE_BRUIJN_H__
// n from 3 to 16
const uint32_t de_bruijn_polys[14]{
0b0000000000000101,
0b0000000000001001,
0b0000000000011011,
0b0000000000110011,
0b0000000001010011,
0b0000000010001101,
0b0000000100100001,
0b0000001000100001,
0b0000010001100001,
0b0000110101000011,
0b0001001001100101,
0b0010101100000011,
0b0101000000001001,
0b1010000101000101};
struct de_bruijn {
public:
size_t init(const uint32_t n);
uint32_t compute(const uint32_t steps);
private:
uint32_t length{};
uint32_t poly{};
uint32_t shift_register{};
};
#endif /*__DE_BRUIJN_H__*/
+1
View File
@@ -131,6 +131,7 @@ ADSBCallsignView::ADSBCallsignView(
nav,
callsign,
8,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& s) {
button_callsign.set_text(s);
});
+9 -28
View File
@@ -81,8 +81,6 @@ void CVSSpamView::start_tx(const uint32_t id) {
return;
}
const uint32_t sample_rate = 250000;
current_file = cvsfiles_dir / file_list[id].filename();
File capture_file;
@@ -99,20 +97,13 @@ void CVSSpamView::start_tx(const uint32_t id) {
return;
}
auto metadata_path = get_metadata_path(current_file);
auto metadata = read_metadata_file(metadata_path);
if (!metadata) {
metadata = capture_metadata{transmitter_model.target_frequency(), sample_rate};
}
auto file_size = capture_file.size();
capture_file.close();
replay_thread.reset();
transmitter_model.disable();
ready_signal = false;
baseband::set_sample_rate(metadata->sample_rate, get_oversample_rate(metadata->sample_rate));
baseband::set_sample_rate(SAMPLE_RATE, get_oversample_rate(SAMPLE_RATE));
auto reader = std::make_unique<FileConvertReader>();
if (auto error = reader->open(current_file)) {
@@ -120,10 +111,7 @@ void CVSSpamView::start_tx(const uint32_t id) {
"Cannot read C16 data.\n"
"Check file format/perms.\n"
"Rate: " +
to_string_dec_uint(metadata->sample_rate) +
"\n"
"Size: " +
to_string_dec_uint(file_size) +
to_string_dec_uint(SAMPLE_RATE) +
"\n"
"Error: " +
std::to_string(static_cast<uint32_t>(error)));
@@ -132,9 +120,9 @@ void CVSSpamView::start_tx(const uint32_t id) {
progressbar.set_value(0);
transmitter_model.set_sampling_rate(get_actual_sample_rate(metadata->sample_rate));
transmitter_model.set_baseband_bandwidth(metadata->sample_rate <= 500000 ? 1750000 : 2500000);
transmitter_model.set_target_frequency(metadata->center_frequency);
transmitter_model.set_sampling_rate(get_actual_sample_rate(SAMPLE_RATE));
transmitter_model.set_baseband_bandwidth(SAMPLE_RATE <= 500000 ? 1750000 : 2500000);
transmitter_model.set_target_frequency(TARGET_FREQUENCY);
transmitter_model.enable();
chThdSleepMilliseconds(100);
@@ -164,7 +152,6 @@ void CVSSpamView::start_random_tx() {
lfsr_v = lfsr_iterate(lfsr_v);
size_t random_index = lfsr_v % file_list.size();
const uint32_t sample_rate = 250000;
current_file = cvsfiles_dir / file_list[random_index].filename();
File capture_file;
@@ -174,19 +161,13 @@ void CVSSpamView::start_random_tx() {
return;
}
auto metadata_path = get_metadata_path(current_file);
auto metadata = read_metadata_file(metadata_path);
if (!metadata) {
metadata = capture_metadata{transmitter_model.target_frequency(), sample_rate};
}
capture_file.close();
replay_thread.reset();
transmitter_model.disable();
ready_signal = false;
baseband::set_sample_rate(metadata->sample_rate, get_oversample_rate(metadata->sample_rate));
baseband::set_sample_rate(SAMPLE_RATE, get_oversample_rate(SAMPLE_RATE));
auto reader = std::make_unique<FileConvertReader>();
if (auto error = reader->open(current_file)) {
@@ -196,9 +177,9 @@ void CVSSpamView::start_random_tx() {
progressbar.set_value(0);
transmitter_model.set_sampling_rate(get_actual_sample_rate(metadata->sample_rate));
transmitter_model.set_baseband_bandwidth(metadata->sample_rate <= 500000 ? 1750000 : 2500000);
transmitter_model.set_target_frequency(metadata->center_frequency);
transmitter_model.set_sampling_rate(get_actual_sample_rate(SAMPLE_RATE));
transmitter_model.set_baseband_bandwidth(SAMPLE_RATE <= 500000 ? 1750000 : 2500000);
transmitter_model.set_target_frequency(TARGET_FREQUENCY);
transmitter_model.enable();
chThdSleepMilliseconds(100);
+3
View File
@@ -16,6 +16,9 @@ using namespace portapack;
namespace ui::external_app::cvs_spam {
constexpr uint32_t SAMPLE_RATE = 250000;
constexpr uint64_t TARGET_FREQUENCY = 433920000;
class CVSSpamView : public View {
public:
explicit CVSSpamView(NavigationView& nav);
+83
View File
@@ -0,0 +1,83 @@
/*
* 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_debug_pmem.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::debug_pmem {
void initialize_app(ui::NavigationView& nav) {
nav.push<DebugDumpView>();
}
} // namespace ui::external_app::debug_pmem
extern "C" {
__attribute__((section(".external_app.app_debug_pmem.application_information"), used)) application_information_t _application_information_debug_pmem = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::debug_pmem::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "DebugPMem",
/*.bitmap_data = */ {
0x54,
0x15,
0x54,
0x15,
0xFF,
0x7F,
0xFC,
0x1F,
0xFF,
0x7F,
0xCC,
0x19,
0xAF,
0x7A,
0x6C,
0x1B,
0xEF,
0x7B,
0xEC,
0x1B,
0xFF,
0x7F,
0xFC,
0x1F,
0xFF,
0x7F,
0x54,
0x15,
0x54,
0x15,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.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
};
}
@@ -0,0 +1,210 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 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.
*/
#include "ui_debug_pmem.hpp"
namespace ui::external_app::debug_pmem {
// Dump pmem, receiver and transmitter models internals in human readable format
bool DebugDumpView::debug_dump_func() {
std::string debug_dir = "DEBUG";
std::filesystem::path filename{};
File pmem_dump_file{};
// create new dump file name and DEBUG directory
ensure_directory(debug_dir);
filename = next_filename_matching_pattern(debug_dir + "/DEBUG_DUMP_????.TXT");
if (filename.empty()) {
dump_output.set("COULD NOT GET DUMP NAME !");
dump_output.set_style(ui::Theme::getInstance()->fg_red);
return false;
}
// dump data fo filename
auto error = pmem_dump_file.create(filename);
if (error) {
dump_output.set("ERROR DUMPING " + filename.filename().string() + " !");
dump_output.set_style(ui::Theme::getInstance()->fg_red);
return false;
}
pmem_dump_file.write_line("FW version: " VERSION_STRING);
pmem_dump_file.write_line("Ext APPS version req'd: 0x" + to_string_hex(VERSION_MD5));
pmem_dump_file.write_line("GCC version: " + to_string_dec_int(__GNUC__) + "." + to_string_dec_int(__GNUC_MINOR__) + "." + to_string_dec_int(__GNUC_PATCHLEVEL__));
// firmware checksum
pmem_dump_file.write_line("Firmware calculated checksum: 0x" + to_string_hex(simple_checksum(FLASH_STARTING_ADDRESS, FLASH_ROM_SIZE), 8));
// write persistent memory
pmem_dump_file.write_line("\n[Persistent Memory]");
// full variables
pmem_dump_file.write_line("structure_version: 0x" + to_string_hex(get_data_structure_version(), 8));
pmem_dump_file.write_line("target_frequency: " + to_string_dec_int(target_frequency()));
pmem_dump_file.write_line("correction_ppb: " + to_string_dec_int(correction_ppb()));
pmem_dump_file.write_line("modem_def_index: " + to_string_dec_uint(get_modem_def_index()));
pmem_dump_file.write_line("serial_format.data_bit: " + to_string_dec_uint(serial_format().data_bits));
pmem_dump_file.write_line("serial_format.parity: " + to_string_dec_uint(serial_format().parity));
pmem_dump_file.write_line("serial_format.stop_bits: " + to_string_dec_uint(serial_format().stop_bits));
pmem_dump_file.write_line("serial_format.bit_order: " + to_string_dec_uint(serial_format().bit_order));
pmem_dump_file.write_line("modem_bw: " + to_string_dec_int(modem_bw()));
pmem_dump_file.write_line("afsk_mark_freq: " + to_string_dec_int(afsk_mark_freq()));
pmem_dump_file.write_line("afsk_space_freq: " + to_string_dec_int(afsk_space_freq()));
pmem_dump_file.write_line("modem_baudrate: " + to_string_dec_int(modem_baudrate()));
pmem_dump_file.write_line("modem_repeat: " + to_string_dec_int(modem_repeat()));
pmem_dump_file.write_line("pocsag_last_address: " + to_string_dec_uint(pocsag_last_address()));
pmem_dump_file.write_line("pocsag_ignore_address: " + to_string_dec_uint(pocsag_ignore_address()));
pmem_dump_file.write_line("tone_mix: " + to_string_dec_uint(tone_mix()));
pmem_dump_file.write_line("hardware_config: " + to_string_dec_uint(config_cpld()));
pmem_dump_file.write_line("recon_config: 0x" + to_string_hex(get_recon_config(), 16));
pmem_dump_file.write_line("recon_repeat_nb: " + to_string_dec_int(recon_repeat_nb()));
pmem_dump_file.write_line("recon_repeat_gain: " + to_string_dec_int(recon_repeat_gain()));
pmem_dump_file.write_line("recon_repeat_delay: " + to_string_dec_int(recon_repeat_delay()));
pmem_dump_file.write_line("converter: " + to_string_dec_int(config_converter()));
pmem_dump_file.write_line("updown_converter: " + to_string_dec_int(config_updown_converter()));
pmem_dump_file.write_line("updown_frequency_rx_correction: " + to_string_dec_int(config_freq_rx_correction_updown()));
pmem_dump_file.write_line("updown_frequency_tx_correction: " + to_string_dec_int(config_freq_tx_correction_updown()));
pmem_dump_file.write_line("lcd_inverted_mode: " + to_string_dec_uint(config_lcd_inverted_mode()));
pmem_dump_file.write_line("converter_frequency_offset: " + to_string_dec_int(config_converter_freq()));
pmem_dump_file.write_line("frequency_rx_correction: " + to_string_dec_uint(config_freq_rx_correction()));
pmem_dump_file.write_line("frequency_tx_correction: " + to_string_dec_uint(config_freq_tx_correction()));
pmem_dump_file.write_line("encoder_dial_sensitivity: " + to_string_dec_uint(encoder_dial_sensitivity()));
pmem_dump_file.write_line("encoder_rate_multiplier: " + to_string_dec_uint(encoder_rate_multiplier()));
pmem_dump_file.write_line("encoder_dial_direction: " + to_string_dec_uint(encoder_dial_direction())); // 0 = normal, 1 = reverse
pmem_dump_file.write_line("config_mode_storage: 0x" + to_string_hex(config_mode_storage_direct(), 8));
pmem_dump_file.write_line("dst_config: 0x" + to_string_hex((uint32_t)config_dst().v, 8));
pmem_dump_file.write_line("fake_brightness_level: " + to_string_dec_uint(fake_brightness_level()));
pmem_dump_file.write_line("menu_color: 0x" + to_string_hex(menu_color().v, 4));
pmem_dump_file.write_line("touchscreen_threshold: " + to_string_dec_uint(touchscreen_threshold()));
// ui_config bits
const auto backlight_timer = portapack::persistent_memory::config_backlight_timer();
pmem_dump_file.write_line("ui_config clkout_freq: " + to_string_dec_uint(clkout_freq()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_enabled: " + to_string_dec_uint(backlight_timer.timeout_enabled()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_seconds: " + to_string_dec_uint(backlight_timer.timeout_seconds()));
pmem_dump_file.write_line("ui_config show_gui_return_icon: " + to_string_dec_uint(show_gui_return_icon()));
pmem_dump_file.write_line("ui_config load_app_settings: " + to_string_dec_uint(load_app_settings()));
pmem_dump_file.write_line("ui_config save_app_settings: " + to_string_dec_uint(save_app_settings()));
pmem_dump_file.write_line("ui_config disable_touchscreen: " + to_string_dec_uint(disable_touchscreen()));
pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(hide_clock()));
pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(clock_with_date()));
pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(clkout_enabled()));
pmem_dump_file.write_line("ui_config apply_fake_brightness: " + to_string_dec_uint(apply_fake_brightness()));
pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(stealth_mode()));
pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(config_login()));
pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(config_splash()));
// ui_config2 bits
pmem_dump_file.write_line("ui_config2 hide_speaker: " + to_string_dec_uint(ui_hide_speaker()));
pmem_dump_file.write_line("ui_config2 hide_converter: " + to_string_dec_uint(ui_hide_converter()));
pmem_dump_file.write_line("ui_config2 hide_stealth: " + to_string_dec_uint(ui_hide_stealth()));
pmem_dump_file.write_line("ui_config2 hide_camera: " + to_string_dec_uint(ui_hide_camera()));
pmem_dump_file.write_line("ui_config2 hide_sleep: " + to_string_dec_uint(ui_hide_sleep()));
pmem_dump_file.write_line("ui_config2 hide_bias_tee: " + to_string_dec_uint(ui_hide_bias_tee()));
pmem_dump_file.write_line("ui_config2 hide_clock: " + to_string_dec_uint(ui_hide_clock()));
pmem_dump_file.write_line("ui_config2 hide_sd_card: " + to_string_dec_uint(ui_hide_sd_card()));
pmem_dump_file.write_line("ui_config2 hide_mute: " + to_string_dec_uint(ui_hide_mute()));
pmem_dump_file.write_line("ui_config2 hide_fake_brightness: " + to_string_dec_uint(ui_hide_fake_brightness()));
pmem_dump_file.write_line("ui_config2 hide_battery_icon: " + to_string_dec_uint(ui_hide_battery_icon()));
pmem_dump_file.write_line("ui_config2 hide_numeric_battery: " + to_string_dec_uint(ui_hide_numeric_battery()));
pmem_dump_file.write_line("ui_config2 theme_id: " + to_string_dec_uint(ui_theme_id()));
pmem_dump_file.write_line("ui_config2 override_batt_calc: " + to_string_dec_uint(ui_override_batt_calc()));
pmem_dump_file.write_line("ui_config2 button_repeat_delay: " + to_string_dec_uint(ui_button_repeat_delay()));
pmem_dump_file.write_line("ui_config2 button_repeat_speed: " + to_string_dec_uint(ui_button_repeat_speed()));
pmem_dump_file.write_line("ui_config2 button_long_press_delay: " + to_string_dec_uint(ui_button_long_press_delay()));
pmem_dump_file.write_line("ui_config2 battery_charge_hint: " + to_string_dec_uint(ui_battery_charge_hint()));
// misc_config bits
pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute()));
pmem_dump_file.write_line("misc_config config_speaker_disable: " + to_string_dec_int(config_speaker_disable()));
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]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(receiver_model.target_frequency()));
pmem_dump_file.write_line("frequency_step: " + to_string_dec_uint(receiver_model.frequency_step()));
pmem_dump_file.write_line("lna: " + to_string_dec_int(receiver_model.lna()));
pmem_dump_file.write_line("vga: " + to_string_dec_int(receiver_model.vga()));
pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(receiver_model.rf_amp()));
pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(receiver_model.baseband_bandwidth()));
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(receiver_model.sampling_rate()));
switch (receiver_model.modulation()) {
case ReceiverModel::Mode::AMAudio:
pmem_dump_file.write_line("modulation: Mode::AMAudio");
break;
case ReceiverModel::Mode::NarrowbandFMAudio:
pmem_dump_file.write_line("modulation: Mode::NarrowbandFMAudio");
break;
case ReceiverModel::Mode::WidebandFMAudio:
pmem_dump_file.write_line("modulation: Mode::WidebandFMAudio");
break;
case ReceiverModel::Mode::SpectrumAnalysis:
pmem_dump_file.write_line("modulation: Mode::SpectrumAnalysis");
break;
case ReceiverModel::Mode::Capture:
pmem_dump_file.write_line("modulation: Mode::Capture");
break;
case ReceiverModel::Mode::AMAudioFMApt:
pmem_dump_file.write_line("modulation: Mode::AMAudioFMApt");
break;
default:
pmem_dump_file.write_line("modulation: !!unknown mode!!");
break;
}
pmem_dump_file.write_line("headphone_volume.centibel: " + to_string_dec_int(receiver_model.headphone_volume().centibel()));
pmem_dump_file.write_line("normalized_headphone_volume: " + to_string_dec_uint(receiver_model.normalized_headphone_volume()));
pmem_dump_file.write_line("am_configuration: " + to_string_dec_uint(receiver_model.am_configuration()));
pmem_dump_file.write_line("nbfm_configuration: " + to_string_dec_uint(receiver_model.nbfm_configuration()));
pmem_dump_file.write_line("wfm_configuration: " + to_string_dec_uint(receiver_model.wfm_configuration()));
// transmitter_model
pmem_dump_file.write_line("\n[Transmitter Model]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(transmitter_model.target_frequency()));
pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(transmitter_model.rf_amp()));
pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(transmitter_model.baseband_bandwidth()));
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate()));
pmem_dump_file.write_line("tx_gain: " + to_string_dec_int(transmitter_model.tx_gain()));
pmem_dump_file.write_line("channel_bandwidth: " + to_string_dec_uint(transmitter_model.channel_bandwidth()));
// on screen information
dump_output.set(filename.filename().string() + " DUMPED !");
dump_output.set_style(ui::Theme::getInstance()->fg_green);
return true;
}
DebugDumpView::DebugDumpView(NavigationView& nav)
: nav_{nav} {
add_children({&dump_output,
&button_exit});
debug_dump_func();
button_exit.on_select = [this](Button&) {
nav_.pop();
};
}
void DebugDumpView::focus() {
button_exit.focus();
}
} // namespace ui::external_app::debug_pmem
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_DEBUG_PMEM_APP_H__
#define __UI_DEBUG_PMEM_APP_H__
#include "portapack_persistent_memory.hpp"
#include "ui_flash_utility.hpp"
using namespace portapack;
using namespace portapack::persistent_memory;
namespace ui::external_app::debug_pmem {
class DebugDumpView : public View {
public:
DebugDumpView(NavigationView& nav);
void focus() override;
std::string title() const override { return "DebugPMem"; };
bool debug_dump_func();
private:
NavigationView& nav_;
Text dump_output{
{0 * 8, 19 * 8, 30 * 8, 16},
""};
Button button_exit{
{22 * 8, 34 * 8, 8 * 8, 32},
"Exit"};
};
} // namespace ui::external_app::debug_pmem
#endif /*__UI_DEBUG_PMEM_APP_H__*/
+14 -4
View File
@@ -192,9 +192,17 @@ set(EXTCPPSRC
external/doom/main.cpp
external/doom/ui_doom.cpp
#screening
# external/screening/main.cpp
# external/screening/ui_screening.cpp
#debug_pmem
external/debug_pmem/main.cpp
external/debug_pmem/ui_debug_pmem.cpp
#scanner
external/scanner/main.cpp
external/scanner/ui_scanner.cpp
#level
external/level/main.cpp
external/level/ui_level.cpp
)
set(EXTAPPLIST
@@ -244,5 +252,7 @@ set(EXTAPPLIST
stopwatch
breakout
doom
# screening
debug_pmem
scanner
level
)
+18 -10
View File
@@ -69,8 +69,9 @@ MEMORY
ram_external_app_wefax_rx (rwx) : org = 0xADDC0000, len = 32k
ram_external_app_breakout (rwx) : org = 0xADDD0000, len = 32k
ram_external_app_doom (rwx) : org = 0xADDE0000, len = 32k
/*ram_external_app_screening (rwx) : org = 0xADDF0000, len = 32k*/
ram_external_app_debug_pmem (rwx) : org = 0xADDF0000, len = 32k
ram_external_app_scanner (rwx) : org = 0xADE00000, len = 32k
ram_external_app_level (rwx) : org = 0xADE10000, len = 32k
}
SECTIONS
@@ -349,15 +350,22 @@ SECTIONS
KEEP(*(.external_app.app_doom.application_information));
*(*ui*external_app*doom*);
} > ram_external_app_doom
/*
.external_app_screening : ALIGN(4) SUBALIGN(4)
.external_app_debug_pmem : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_screening.application_information));
*(*ui*external_app*screening*);
} > ram_external_app_screening
*/
KEEP(*(.external_app.app_debug_pmem.application_information));
*(*ui*external_app*debug_pmem*);
} > ram_external_app_debug_pmem
.external_app_scanner : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_scanner.application_information));
*(*ui*external_app*scanner*);
} > ram_external_app_scanner
.external_app_level : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_level.application_information));
*(*ui*external_app*level*);
} > ram_external_app_level
}
@@ -67,6 +67,7 @@ void DebugFontsView::paint(Painter& painter) {
line_pos = display_font(painter, 32, Theme::getInstance()->bg_darkest, "Fixed 8x16", true);
display_font(painter, line_pos + 16, Theme::getInstance()->bg_darkest_small, "Fixed 5x8", false);
paint_zoomed_text(painter);
}
void DebugFontsView::update_address_text() {
@@ -74,16 +75,29 @@ void DebugFontsView::update_address_text() {
text_address.set("0x" + to_string_hex(ascii_value, 2));
}
void DebugFontsView::paint_zoomed_text(Painter& painter) {
if (field_zoom_level.value() == 0) return;
uint8_t cursor_pos = field_cursor.value();
painter.draw_char({screen_width / 2, screen_height / 2},
*Theme::getInstance()->bg_darkest,
(char)(cursor_pos + 0x20), field_zoom_level.value());
}
DebugFontsView::DebugFontsView(NavigationView& nav)
: nav_{nav} {
add_children({&field_cursor,
&text_address});
&text_address,
&field_zoom_level});
set_focusable(true);
field_cursor.on_change = [&](int32_t) {
update_address_text();
set_dirty();
};
field_zoom_level.on_change = [&](int32_t) {
set_dirty();
};
}
void DebugFontsView::focus() {
@@ -46,10 +46,17 @@ class DebugFontsView : public View {
private:
uint16_t display_font(Painter& painter, uint16_t y_offset, const Style* font_style, std::string_view font_name, bool is_big_font);
void update_address_text();
void paint_zoomed_text(Painter& painter);
NumberField field_cursor{
{0 * 8, 0 * 8},
4,
{0, 1000},
1,
' '};
NumberField field_zoom_level{
{6 * 8, 0 * 8},
4,
{0, 1000},
1,
' '};
+1
View File
@@ -227,6 +227,7 @@ void HopperView::save_list() {
nav_,
filename_buffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& value) {
auto path = hopper_dir / (value + ".PHOP");
+2
View File
@@ -189,6 +189,7 @@ void LCRView::on_button_set_am(NavigationView& nav, int16_t button_id) {
nav,
litteral[button_id],
7,
ENTER_KEYBOARD_MODE_ALPHA,
[this, button_id](std::string& buffer) {
texts[button_id].set(buffer);
});
@@ -257,6 +258,7 @@ LCRView::LCRView(NavigationView& nav) {
nav,
rgsb,
4,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
button_set_rgsb.set_text(buffer);
});
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_level.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::level {
void initialize_app(ui::NavigationView& nav) {
nav.push<LevelView>();
}
} // namespace ui::external_app::level
extern "C" {
__attribute__((section(".external_app.app_level.application_information"), used)) application_information_t _application_information_level = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::level::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Level",
/*.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::green().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
// this has to be the biggest baseband used by the app. Level is using AM,WFM,NFM,AMFM,SPEC and NFM is the biggest
/*.m4_app_tag = portapack::spi_flash::image_tag_nfm */ {'P', 'N', 'F', 'M'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -33,7 +33,7 @@ using namespace portapack;
using namespace tonekey;
using portapack::memory::map::backup_ram;
namespace ui {
namespace ui::external_app::level {
// 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) {
@@ -130,9 +130,16 @@ LevelView::LevelView(NavigationView& nav)
freqman_set_modulation_option(field_mode);
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
if (v != -1) {
change_mode(v);
static freqman_index_t last_mode = WFM_MODULATION;
if (v > SPEC_MODULATION) {
if (last_mode == SPEC_MODULATION)
v = AM_MODULATION;
else
v = SPEC_MODULATION;
field_mode.set_selected_index(v);
}
last_mode = v;
change_mode(v);
};
field_mode.set_by_value(radio_mode); // Reflect the mode into the manual selector
field_bw.set_selected_index(radio_bw);
@@ -277,15 +284,6 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); };
break;
case AMFM_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::AMAudioFMApt);
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
break;
case SPEC_MODULATION:
audio_sampling_rate = audio::Rate::Hz_24000;
freqman_set_bandwidth_option(new_mod, field_bw);
@@ -338,4 +336,4 @@ void LevelView::on_freqchg(int64_t freq) {
button_frequency.set_text("<" + to_string_short_freq(freq) + " MHz>");
}
} /* namespace ui */
} // namespace ui::external_app::level
@@ -39,7 +39,7 @@
#include "ui_receiver.hpp"
#include "ui_spectrum.hpp"
namespace ui {
namespace ui::external_app::level {
class LevelView : public View {
public:
@@ -211,6 +211,6 @@ class LevelView : public View {
}};
};
} /* namespace ui */
} // namespace ui::external_app::level
#endif
+1
View File
@@ -311,6 +311,7 @@ LGEView::LGEView(NavigationView& nav) {
nav,
nickname,
15,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
button_text.set_text(buffer);
});
+122
View File
@@ -23,6 +23,7 @@
#include "baseband_api.hpp"
#include "audio.hpp"
#include "portapack.hpp"
#include "ui_textentry.hpp"
using namespace portapack;
@@ -42,6 +43,7 @@ MetronomeView::MetronomeView(NavigationView& nav)
&field_unaccent_beep_tune,
&field_beep_flash_duration,
&field_bpm,
&button_enter_tap_tempo,
&progressbar,
});
@@ -59,6 +61,14 @@ MetronomeView::MetronomeView(NavigationView& nav)
}
};
button_enter_tap_tempo.on_select = [this](Button&) {
auto tap_tempo_view = nav_.push<MetronomeTapTempoView>(field_bpm.value());
tap_tempo_view->on_apply = [this](uint16_t bpm) {
field_bpm.set_value(bpm);
};
};
field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first
field_volume.set_value(99);
@@ -174,4 +184,116 @@ void MetronomeView::run() {
}
}
MetronomeTapTempoView::MetronomeTapTempoView(NavigationView& nav, uint16_t bpm)
: nav_{nav},
bpm_{bpm} {
add_children({
&button_input,
&button_tap,
&button_cancel,
&button_apply,
});
bpm_when_entered_ = bpm; // save for if user cancel
// im aware that we have duplicated painter which means in this app, weo have two painter instances
// here is the reason why this is necessary:
// We need to draw the bpm big font once when enter, which would be at bad timing in constructor,
// cuz it happened before the view is pushed to nav, which casued it actually didn't draw
// which leads me have to override the paint func from father and draw inside of it.
//
// BUT I can't completely package the draw logic inside of the paint func,
// cuz set_dirty has flaw and cause screen flicker during the char changes, if i just package there and use set_dirty()
Painter painter_instance_2;
button_input.on_select = [this](Button&) {
input_buffer = to_string_dec_uint(bpm_);
text_prompt(
nav_,
input_buffer,
3,
ENTER_KEYBOARD_MODE_DIGITS,
[this](std::string& buffer) {
if (buffer.empty()) {
return;
}
bpm_ = atoi(buffer.c_str());
if (on_apply) {
on_apply(bpm_);
}
});
};
button_tap.on_select = [&](Button&) {
on_tap(painter_instance_2);
};
button_apply.on_select = [this](Button&) {
// it's dynamically applied in tap handler
// the design allow user to hear changes before apply
nav_.pop();
};
button_cancel.on_select = [this](Button&) {
bpm_ = bpm_when_entered_;
if (on_apply) {
on_apply(bpm_);
}
nav_.pop();
};
}
void MetronomeTapTempoView::focus() {
button_tap.focus();
}
void MetronomeTapTempoView::paint(Painter& painter) {
View::paint(painter);
painter.draw_char({(0 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + bpm_ / 100, 4);
painter.draw_char({(1 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + (bpm_ / 10) % 10, 4);
painter.draw_char({(2 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + bpm_ % 10, 4);
}
/*
NB: i don't really know if the cpu clock is 1000Hz AKA 1ms per tick for chTimeNow()
but it should be, refering to the stop watch app.
and also i compared with my real metronome and it's very close
so I assume it's 1ms per tick
*/
void MetronomeTapTempoView::on_tap(Painter& painter) {
/* ^ NB: this painter accepted from painter_instance_2*/
systime_t current_time = chTimeNow();
if (last_tap_time > 0) {
uint32_t interval_ms = current_time - last_tap_time;
if (interval_ms > 100) {
uint16_t this_time_bpm = 60000 / interval_ms;
if (this_time_bpm > 0 && this_time_bpm < 400) {
bpms_deque.push_back(this_time_bpm);
if (bpms_deque.size() > 4) { // one bar length cuz most music tempo is quarter note as 1 beat
bpms_deque.pop_front();
}
// avg
uint32_t sum = 0;
for (auto& bpm : bpms_deque) {
sum += bpm;
}
bpm_ = sum / bpms_deque.size();
if (on_apply) {
on_apply(bpm_);
}
painter.draw_char({(0 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + bpm_ / 100, 4);
painter.draw_char({(1 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + (bpm_ / 10) % 10, 4);
painter.draw_char({(2 * 16) * 4 + 2 * 16, 3 * 16}, *Theme::getInstance()->fg_light, '0' + bpm_ % 10, 4);
}
}
}
last_tap_time = current_time;
}
} // namespace ui::external_app::metronome
@@ -27,6 +27,8 @@
#include "audio.hpp"
#include "ch.h"
#include <deque>
namespace ui::external_app::metronome {
class MetronomeView : public View {
@@ -73,6 +75,11 @@ class MetronomeView : public View {
1,
' '};
Button button_enter_tap_tempo{
{(sizeof("BPM:") + 6) * 8, 1 * 16, (sizeof("Tap Tempo") + 3) * 8, 16},
"Tap Tempo",
};
NumberField field_rythm_unaccent_time{// e.g. 3 in 3/4 beat
{(sizeof("Rhythm:") + 1) * 8, 4 * 16},
2,
@@ -121,6 +128,45 @@ class MetronomeView : public View {
{0 * 16, 8 * 16, screen_width, screen_height - 14 * 16}};
};
class MetronomeTapTempoView : public View {
public:
std::function<void(uint16_t)> on_apply{};
MetronomeTapTempoView(NavigationView& nav, uint16_t bpm);
std::string title() const override { return "Tap.T"; };
void focus() override;
void paint(Painter& painter) override;
private:
void on_tap(Painter& painter);
NavigationView& nav_;
uint16_t bpm_{0};
uint16_t bpm_when_entered_{0}; // this pass from MetronomeView and need to restore if user cancel
std::deque<uint16_t> bpms_deque = {0}; // take average for recent taps to debounce
uint32_t last_tap_time{0};
std::string input_buffer{""}; // needed by text_prompt
Button button_input{
{0, 0, screen_width, 2 * 16},
"Input BPM"};
Button button_tap{
{0, 8 * 16, screen_width, 7 * 16},
"Tap BPM"};
Button button_cancel{
{1, 17 * 16, screen_width / 2 - 4, 2 * 16},
"Cancel"};
Button button_apply{
{1 + screen_width / 2 + 1, 17 * 16, screen_width / 2 - 4, 2 * 16},
"Apply"};
};
} // namespace ui::external_app::metronome
#endif /*__UI_METRONOME_H__*/
+1 -1
View File
@@ -99,7 +99,7 @@ static msg_t loopthread_fn(void* arg) {
}
void MorseView::on_set_text(NavigationView& nav) {
text_prompt(nav, buffer, 28);
text_prompt(nav, buffer, 28, ENTER_KEYBOARD_MODE_ALPHA);
}
void MorseView::focus() {
@@ -210,6 +210,7 @@ OOKEditorAppView::OOKEditorAppView(NavigationView& nav)
nav,
outputFileBuffer,
64,
ENTER_KEYBOARD_MODE_ALPHA,
[this](std::string& buffer) {
on_save_file(buffer);
});
@@ -263,6 +264,7 @@ OOKEditorAppView::OOKEditorAppView(NavigationView& nav)
nav,
ook_data.payload,
100,
ENTER_KEYBOARD_MODE_DIGITS,
[this](std::string& s) {
text_payload.set(s);
draw_waveform();
@@ -83,6 +83,7 @@ OOKBruteView::OOKBruteView(NavigationView& nav)
nav_,
text_input_buffer,
8, // currently longest is princeton
ENTER_KEYBOARD_MODE_DIGITS,
[this](std::string& buffer) {
field_start.set_value(atoi(buffer.c_str()));
validate_start_stop();
@@ -100,6 +101,7 @@ OOKBruteView::OOKBruteView(NavigationView& nav)
nav_,
text_input_buffer,
8, // currently longest is princeton
ENTER_KEYBOARD_MODE_DIGITS,
[this](std::string& buffer) {
field_stop.set_value(atoi(buffer.c_str()));
validate_start_stop();
@@ -122,6 +122,7 @@ bool PlaylistEditorView::on_create_ppl() {
nav_,
current_ppl_name_buffer,
100,
ENTER_KEYBOARD_MODE_ALPHA,
[&](std::string& s) {
current_ppl_name_buffer = s;
@@ -307,6 +308,7 @@ PlaylistItemEditView::PlaylistItemEditView(
nav_,
delay_str,
100,
ENTER_KEYBOARD_MODE_ALPHA,
[&](std::string& s) {
delay_ = atoi(s.c_str());
field_delay.set_value(delay_);
+2 -2
View File
@@ -330,7 +330,7 @@ RemoteAppView::RemoteAppView(
field_title.on_select = [this, &nav](TextField&) {
temp_buffer_ = model_.name;
text_prompt(nav_, temp_buffer_, text_edit_max, [this](std::string& new_name) {
text_prompt(nav_, temp_buffer_, text_edit_max, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& new_name) {
model_.name = new_name;
refresh_ui();
set_needs_save();
@@ -339,7 +339,7 @@ RemoteAppView::RemoteAppView(
field_filename.on_select = [this, &nav](TextField&) {
temp_buffer_ = remote_path_.stem().string();
text_prompt(nav_, temp_buffer_, text_edit_max, [this](std::string& new_name) {
text_prompt(nav_, temp_buffer_, text_edit_max, ENTER_KEYBOARD_MODE_ALPHA, [this](std::string& new_name) {
rename_remote(new_name);
refresh_ui();
});
+51
View File
@@ -0,0 +1,51 @@
/*
* 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_scanner.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::scanner {
void initialize_app(ui::NavigationView& nav) {
nav.push<ScannerView>();
}
} // namespace ui::external_app::scanner
extern "C" {
__attribute__((section(".external_app.app_scanner.application_information"), used)) application_information_t _application_information_scanner = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::scanner::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Scanner",
/*.bitmap_data = */ {0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x01, 0x80, 0x01, 0xC3, 0x00, 0xE0, 0xFF, 0xEF, 0xFF, 0xC0, 0x00, 0x83, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::RX,
/*.desired_menu_position = */ -1,
// this has to be the biggest baseband used by the app. Scanner is using AM,WFM,NFM and NFM is the biggest
/*.m4_app_tag = portapack::spi_flash::image_tag_scanner */ {'P', 'N', 'F', 'M'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -28,10 +28,11 @@
#include "ui_freqman.hpp"
#include "file_path.hpp"
using namespace ui;
using namespace portapack;
namespace fs = std::filesystem;
namespace ui {
namespace ui::external_app::scanner {
ScannerThread::ScannerThread(std::vector<rf::Frequency> frequency_list)
: frequency_list_{std::move(frequency_list)} {
@@ -451,13 +452,14 @@ ScannerView::ScannerView(
// Mode field was changed (AM/NFM/WFM)
field_mode.on_change = [this](size_t, OptionsField::value_t v) {
static freqman_index_t last_mode = AM_MODULATION;
// initialize to a value under SPEC
static freqman_index_t last_mode = WFM_MODULATION;
// unsupported SPEC mode fix
if (v == SPEC_MODULATION) {
if (last_mode == AM_MODULATION)
v = WFM_MODULATION;
else
if (v >= SPEC_MODULATION) {
if (last_mode == WFM_MODULATION)
v = AM_MODULATION;
else
v = WFM_MODULATION;
field_mode.set_selected_index(v);
}
last_mode = v;
@@ -725,14 +727,6 @@ void ScannerView::change_mode(freqman_index_t new_mod) {
field_bw.set_by_value(receiver_model.wfm_configuration());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
break;
case AMFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt);
receiver_model.set_amfm_configuration(5);
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
break;
default:
break;
}
@@ -773,5 +767,4 @@ void ScannerView::restart_scan() {
start_scan_thread(); // RESTART SCANNER THREAD in selected mode
}
} /* namespace ui */
} // namespace ui::external_app::scanner
@@ -35,12 +35,14 @@
#include "ui_mictx.hpp"
#include "ui_receiver.hpp"
using namespace ui;
namespace ui::external_app::scanner {
#define SCANNER_SLEEP_MS 50 // ms that Scanner Thread sleeps per loop
#define STATISTICS_UPDATES_PER_SEC 10
#define MAX_FREQ_LOCK 10 // # of 50ms cycles scanner locks into freq when signal detected, to verify signal is not spurious
namespace ui {
// TODO: There is too much duplicated data in these classes.
// ScannerThread should just use more from the View.
// Or perhaps ScannerThread should just be in the View.
@@ -314,5 +316,4 @@ class ScannerView : public View {
this->on_statistics_update(static_cast<const ChannelStatisticsMessage*>(p)->statistics);
}};
};
} /* namespace ui */
} // namespace ui::external_app::scanner
+7 -5
View File
@@ -1,6 +1,8 @@
// CVS Spam app by RocketGod (@rocketgod-git) https://betaskynet.com
// Original .cu8 files by @jimilinuxguy https://github.com/jimilinuxguy/customer-assistance-buttons-sdr
// If you can read this, you're a nerd. :P
// Come join us at https://discord.gg/thepiratesreborn
// RocketGod's Shopping Cart Lock app
// https://betaskynet.com
#include "ui.hpp"
#include "shoppingcart_lock.hpp"
#include "ui_navigation.hpp"
@@ -57,10 +59,10 @@ __attribute__((section(".external_app.app_shoppingcart_lock.application_informat
0x00,
},
/*.icon_color = */ ui::Color::red().v,
/*.menu_location = */ app_location_t::TX,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk_rx */ {'P', 'A', 'T', 'X'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
/*.m4_app_tag = portapack::spi_flash::image_tag_audio_tx */ {'P', 'A', 'T', 'X'},
/*.m4_app_offset = */ 0x00000000,
};
}
@@ -1,5 +1,8 @@
// RocketGod's Shopping Cart Lock app
// https://betaskynet.com
// CVS Spam app by RocketGod (@rocketgod-git) https://betaskynet.com
// Original .cu8 files by @jimilinuxguy https://github.com/jimilinuxguy/customer-assistance-buttons-sdr
// If you can read this, you're a nerd. :P
// Come join us at https://discord.gg/thepiratesreborn
#include "shoppingcart_lock.hpp"
using namespace portapack;
@@ -48,7 +51,6 @@ void ShoppingCartLock::stop() {
audio::output::stop();
log_event("... Resetting State Variables");
transmitter_model.disable();
ready_signal = false;
thread_sync_complete = false;
looping = false;
@@ -110,18 +112,24 @@ std::string ShoppingCartLock::list_wav_files() {
}
void ShoppingCartLock::wait_for_thread() {
uint32_t timeout = 100;
uint32_t timeout = 1000;
while (!ready_signal && timeout > 0) {
chThdYield();
timeout--;
}
if (!ready_signal) {
log_event("!!! Timeout waiting for ReplayThread");
}
}
void ShoppingCartLock::restart_playback() {
auto reader = std::make_unique<WAVFileReader>();
std::string file_path = (wav_dir / current_file).string();
if (!reader->open(file_path)) return;
if (!reader->open(file_path)) {
log_event("!!! Failed to reopen " + current_file + " for restart");
return;
}
replay_thread = std::make_unique<ReplayThread>(
std::move(reader),
@@ -133,9 +141,8 @@ void ShoppingCartLock::restart_playback() {
EventDispatcher::send_message(message);
});
log_event(">> SENDING <<");
log_event(">> RESTARTING AUDIO <<");
audio::output::start();
transmitter_model.enable();
}
void ShoppingCartLock::play_audio(const std::string& filename, bool loop) {
@@ -166,33 +173,24 @@ void ShoppingCartLock::play_audio(const std::string& filename, bool loop) {
wait_for_thread();
log_event("... Configuring Baseband");
const uint32_t bb_sample_rate = 1536000;
const uint32_t decimation = bb_sample_rate / wav_sample_rate;
baseband::set_sample_rate(wav_sample_rate);
audio::set_rate(wav_sample_rate <= 12000 ? audio::Rate::Hz_12000 : wav_sample_rate <= 24000 ? audio::Rate::Hz_24000
: audio::Rate::Hz_48000);
baseband::set_audiotx_config(
bb_sample_rate / decimation,
wav_sample_rate,
0.0f,
0.0f,
5.0f,
wav_bits_per_sample,
wav_bits_per_sample,
0,
true,
false,
false,
false,
false);
baseband::set_sample_rate(wav_sample_rate);
log_event("... Starting Audio Output");
audio::output::start();
log_event("... Setting Max Volume");
audio::headphone::set_volume(audio::headphone::volume_range().max);
transmitter_model.enable();
log_event(">>> Playback Started <<<");
volume_t max_volume = audio::headphone::volume_range().max;
audio::headphone::set_volume(max_volume);
}
ShoppingCartLock::ShoppingCartLock(NavigationView& nav)
@@ -225,9 +223,6 @@ ShoppingCartLock::ShoppingCartLock(NavigationView& nav)
log_event("[+] INITIALIZATION COMPLETE");
log_event("[+] PORTAPACK ARMED");
log_event("[*] STATUS: READY");
log_event("This app use speaker to");
log_event("produce LF signal, but");
log_event("also trigger radio TX");
}
ShoppingCartLock::~ShoppingCartLock() {
@@ -235,4 +230,4 @@ ShoppingCartLock::~ShoppingCartLock() {
baseband::shutdown();
}
} // namespace ui::external_app::shoppingcart_lock
} // namespace ui::external_app::shoppingcart_lock
@@ -1,5 +1,8 @@
// RocketGod's Shopping Cart Lock app
// https://betaskynet.com
// CVS Spam app by RocketGod (@rocketgod-git) https://betaskynet.com
// Original .cu8 files by @jimilinuxguy https://github.com/jimilinuxguy/customer-assistance-buttons-sdr
// If you can read this, you're a nerd. :P
// Come join us at https://discord.gg/thepiratesreborn
#pragma once
#include "ui_widget.hpp"
@@ -27,8 +30,8 @@ class ShoppingCartLock : public View {
void focus() override;
private:
static constexpr size_t BUFFER_SIZE = 8192;
static constexpr size_t NUM_BUFFERS = 8;
static constexpr size_t BUFFER_SIZE = 512;
static constexpr size_t NUM_BUFFERS = 2;
const std::string shoppingcart_lock_file{"shopping_cart_lock.wav"};
const std::string shoppingcart_unlock_file{"shopping_cart_unlock.wav"};
@@ -56,7 +56,7 @@ SpectrumInputTextView::~SpectrumInputTextView() {
}
void SpectrumInputTextView::on_set_text(NavigationView& nav) {
text_prompt(nav, buffer, 300);
text_prompt(nav, buffer, 300, ENTER_KEYBOARD_MODE_DIGITS);
}
void SpectrumInputTextView::focus() {
+53 -14
View File
@@ -62,6 +62,9 @@ bool but_SELECT = false;
static int x_pos{0};
static int y_pos{0};
static int rotation_state = 0;
static int fg_color;
static int bg_color;
@@ -259,25 +262,61 @@ void Initialize(unsigned char c) {
boardX = 0;
boardY = 4;
copyCoordinates(X, Y, c - 1);
rotation_state = 0;
}
void Rotate() {
short pivotX = X[1];
short pivotY = Y[1];
short newX[4];
short newY[4];
for (int i = 0; i < 4; i++) {
short tmp = X[i], tmp2 = Y[i];
newX[i] = pivotX + pivotY - tmp2;
newY[i] = tmp + pivotX - pivotY;
if (OutOfBounds(boardY + newY[i], boardX + newX[i]) || board[boardX + newX[i]][boardY + newY[i]] != 0) return;
short newX[4], newY[4];
int next_state = (rotation_state + 1) % 4;
if (colorIndex == 2) {
return;
}
DeleteFigure();
for (int i = 0; i < 4; i++) {
X[i] = newX[i];
Y[i] = newY[i];
const short kick_tests_I[4][5][2] = {
{{0, 0}, {-2, 0}, {1, 0}, {-2, -1}, {1, 2}},
{{0, 0}, {-1, 0}, {2, 0}, {-1, 2}, {2, -1}},
{{0, 0}, {2, 0}, {-1, 0}, {2, 1}, {-1, -2}},
{{0, 0}, {1, 0}, {-2, 0}, {1, -2}, {-2, 1}}};
const short kick_tests_other[4][5][2] = {
{{0, 0}, {-1, 0}, {-1, 1}, {0, -2}, {-1, -2}},
{{0, 0}, {1, 0}, {1, -1}, {0, 2}, {1, 2}},
{{0, 0}, {1, 0}, {1, 1}, {0, -2}, {1, -2}},
{{0, 0}, {-1, 0}, {-1, -1}, {0, 2}, {-1, 2}}};
bool is_I_tetromino = (colorIndex == 1);
const short(*kick_tests)[5][2] = is_I_tetromino ? kick_tests_I : kick_tests_other;
for (int test = 0; test < 5; test++) {
short kickX = kick_tests[rotation_state][test][0];
short kickY = kick_tests[rotation_state][test][1];
for (int i = 0; i < 4; i++) {
short tmpX = X[i] - X[1];
short tmpY = Y[i] - Y[1];
newX[i] = X[1] - tmpY;
newY[i] = Y[1] + tmpX;
int testX = boardX + newX[i] + kickX;
int testY = boardY + newY[i] + kickY;
if (OutOfBounds(testY, testX) || (testX >= 0 && board[testX][testY] != 0)) {
goto next_test;
}
}
DeleteFigure();
for (int i = 0; i < 4; i++) {
X[i] = newX[i];
Y[i] = newY[i];
}
boardX += kickX;
boardY += kickY;
rotation_state = next_state;
DrawFigure();
return;
next_test:
continue;
}
DrawFigure();
}
void DrawFigure() {
+3 -2
View File
@@ -32,7 +32,8 @@ namespace ui {
AlphanumView::AlphanumView(
NavigationView& nav,
std::string& str,
size_t max_length)
size_t max_length,
uint8_t enter_mode)
: TextEntryView(nav, str, max_length) {
size_t n;
@@ -76,7 +77,7 @@ AlphanumView::AlphanumView(
n++;
}
set_mode(mode);
set_mode(enter_mode);
button_mode.on_select = [this](Button&) {
set_mode(mode + 1);
+1 -1
View File
@@ -37,7 +37,7 @@ namespace ui {
class AlphanumView : public TextEntryView {
public:
AlphanumView(NavigationView& nav, std::string& str, size_t max_length);
AlphanumView(NavigationView& nav, std::string& str, size_t max_length, uint8_t enter_mode);
AlphanumView(const AlphanumView&) = delete;
AlphanumView(AlphanumView&&) = delete;
+4 -2
View File
@@ -31,8 +31,9 @@ void text_prompt(
NavigationView& nav,
std::string& str,
size_t max_length,
uint8_t mode,
std::function<void(std::string&)> on_done) {
text_prompt(nav, str, str.length(), max_length, on_done);
text_prompt(nav, str, str.length(), max_length, mode, on_done);
}
void text_prompt(
@@ -40,8 +41,9 @@ void text_prompt(
std::string& str,
uint32_t cursor_pos,
size_t max_length,
uint8_t mode,
std::function<void(std::string&)> on_done) {
auto te_view = nav.push<AlphanumView>(str, max_length);
auto te_view = nav.push<AlphanumView>(str, max_length, mode);
te_view->set_cursor(cursor_pos);
te_view->on_changed = [on_done](std::string& value) {
if (on_done)
+7
View File
@@ -26,6 +26,11 @@
#include "ui.hpp"
#include "ui_navigation.hpp"
#define ENTER_KEYBOARD_MODE_ALPHA 0
#define ENTER_KEYBOARD_MODE_DIGITS 1
#define ENTER_KEYBOARD_MODE_SYMBOLS 2
#define ENTER_KEYBOARD_MODE_HEX 3
namespace ui {
class TextEntryView : public View {
@@ -62,6 +67,7 @@ void text_prompt(
NavigationView& nav,
std::string& str,
size_t max_length,
uint8_t mode,
std::function<void(std::string&)> on_done = nullptr);
void text_prompt(
@@ -69,6 +75,7 @@ void text_prompt(
std::string& str,
uint32_t cursor_pos,
size_t max_length,
uint8_t mode, // enter mode: 123 abc etc
std::function<void(std::string&)> on_done = nullptr);
} /* namespace ui */
+15 -17
View File
@@ -24,8 +24,6 @@
#include "ui_navigation.hpp"
#include "bmp_modal_warning.hpp"
#include "bmp_splash.hpp"
#include "event_m0.hpp"
#include "portapack_persistent_memory.hpp"
#include "portapack_shared_memory.hpp"
@@ -44,7 +42,6 @@
#include "ui_font_fixed_8x16.hpp"
#include "ui_freqman.hpp"
#include "ui_iq_trim.hpp"
#include "ui_level.hpp"
#include "ui_looking_glass_app.hpp"
#include "ui_mictx.hpp"
@@ -52,7 +49,7 @@
#include "ui_pocsag_tx.hpp"
#include "ui_rds.hpp"
#include "ui_recon.hpp"
//#include "ui_scanner.hpp"
// #include "ui_scanner.hpp"
#include "ui_sd_over_usb.hpp"
#include "ui_search.hpp"
#include "ui_settings.hpp"
@@ -133,22 +130,13 @@ const NavigationView::AppList NavigationView::appList = {
{"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, new ViewFactory<AISAppView>()},
{"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSRXView>()},
{"audio", "Audio", RX, Color::green(), &bitmap_icon_speaker, new ViewFactory<AnalogAudioView>()},
//{"blecomm", "BLE Comm", RX, ui::Color::orange(), &bitmap_icon_btle, new ViewFactory<BLECommView>()},
{"blerx", "BLE Rx", RX, Color::green(), &bitmap_icon_btle, new ViewFactory<BLERxView>()},
{"ert", "ERT Meter", RX, Color::green(), &bitmap_icon_ert, new ViewFactory<ERTAppView>()},
{"level", "Level", RX, Color::green(), &bitmap_icon_options_radio, new ViewFactory<LevelView>()},
{"pocsag", "POCSAG", RX, Color::green(), &bitmap_icon_pocsag, new ViewFactory<POCSAGAppView>()},
{"radiosonde", "Radiosnde", RX, Color::green(), &bitmap_icon_sonde, new ViewFactory<SondeView>()},
// {"scanner", "Scanner", RX, Color::green(), &bitmap_icon_scanner, new ViewFactory<ScannerView>()},
{"search", "Search", RX, Color::yellow(), &bitmap_icon_search, new ViewFactory<SearchView>()},
{"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<SubGhzDView>()},
{"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, new ViewFactory<WeatherView>()},
//{"fskrx", "FSK RX", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory<FskxRxMainView>()}, //for JT
//{"dmr", "DMR", RX, Color::dark_grey(), &bitmap_icon_dmr, new ViewFactory<NotImplementedView>()},
//{"sigfox", "SIGFOX", RX, Color::dark_grey(), &bitmap_icon_fox, new ViewFactory<NotImplementedView>()},
//{"lora", "LoRa", RX, Color::dark_grey(), &bitmap_icon_lora, new ViewFactory<NotImplementedView>()},
//{"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 ********************************************************************/
{"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>()},
@@ -158,7 +146,7 @@ const NavigationView::AppList NavigationView::appList = {
{"rdstx", "RDS", TX, ui::Color::green(), &bitmap_icon_rds, new ViewFactory<RDSView>()},
{"soundbrd", "Soundbrd", TX, ui::Color::green(), &bitmap_icon_soundboard, new ViewFactory<SoundBoardView>()},
{"touchtune", "TouchTune", TX, ui::Color::green(), &bitmap_icon_touchtunes, new ViewFactory<TouchTunesView>()},
{"signalgen", "Signal Gen", TX, Color::green(), &bitmap_icon_cwgen, new ViewFactory<SigGenView>()},
{"signalgen", "SignalGen", TX, Color::green(), &bitmap_icon_cwgen, new ViewFactory<SigGenView>()},
/* UTILITIES *************************************************************/
{"filemanager", "File Manager", UTILITIES, Color::green(), &bitmap_icon_dir, new ViewFactory<FileManagerView>()},
{"freqman", "Freq. Manager", UTILITIES, Color::green(), &bitmap_icon_freqman, new ViewFactory<FrequencyManagerView>()},
@@ -355,7 +343,7 @@ void SystemStatusView::on_battery_data(const BatteryStateMessage* msg) {
// Check if charging state changed to charging
static bool was_charging = false;
if (msg->on_charger && !was_charging) {
if (msg->on_charger && !was_charging && pmem::ui_battery_charge_hint()) {
// Only show charging modal when transitioning to charging state
nav_.display_modal(
"CHARGING",
@@ -1049,7 +1037,12 @@ SplashScreenView::SplashScreenView(NavigationView& nav)
void SplashScreenView::paint(Painter&) {
if (!portapack::display.draw_bmp_from_sdcard_file({0, 0}, splash_dot_bmp))
// ^ try draw bmp file from sdcard at (0,0), and the (0,0) already bypassed the status bar, so actual pos is (0, STATUS_BAR_HEIGHT)
portapack::display.draw_bmp_from_bmp_hex_arr({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, (const uint8_t[]){0x29, 0x18, 0x16});
portapack::display.draw_bitmap({screen_width / 2 - 120,
screen_height / 2},
bitmap_titlebar_image.size,
bitmap_titlebar_image.data,
Theme::getInstance()->bg_darkest->foreground,
Theme::getInstance()->bg_darkest->background, 3);
// ^ draw BMP HEX arr in firmware, note that the BMP HEX arr only cover the image part (instead of fill the screen with background, this position is located it in the center)
}
@@ -1144,7 +1137,12 @@ ModalMessageView::ModalMessageView(
}
void ModalMessageView::paint(Painter& painter) {
if (!compact) portapack::display.draw_bmp_from_bmp_hex_arr({100, 48}, modal_warning_bmp, (const uint8_t[]){0, 0, 0});
if (!compact) portapack::display.draw_bitmap({screen_width / 2 - 3 * 16 / 2,
screen_height / 2 - 3 * 16 / 2 - 100},
bitmap_icon_utilities.size,
bitmap_icon_utilities.data,
Theme::getInstance()->bg_darkest->foreground,
Theme::getInstance()->bg_darkest->background, 3);
// Break lines.
auto lines = split_string(message_, '\n');
+54 -25
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* copyleft 2025 Whiterose of the Dark Army
*
* This file is part of PortaPack.
*
@@ -646,31 +647,58 @@ void ILI9341::draw_bitmap(
const ui::Size size,
const uint8_t* const pixels,
const ui::Color foreground,
const ui::Color background) {
// Not a transparent background
if (ui::Color::magenta().v != background.v) {
lcd_start_ram_write(p, size);
const ui::Color background,
uint8_t zoom_level) {
if (zoom_level <= 1) {
// Not a transparent background
if (ui::Color::magenta().v != background.v) {
lcd_start_ram_write(p, size);
const size_t count = size.width() * size.height();
for (size_t i = 0; i < count; i++) {
const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
io.lcd_write_pixel(pixel ? foreground : background);
}
} else {
int x = p.x();
int y = p.y();
int maxX = x + size.width();
const size_t count = size.width() * size.height();
for (size_t i = 0; i < count; i++) {
const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
if (pixel) {
draw_pixel(ui::Point(x, y), foreground);
const size_t count = size.width() * size.height();
for (size_t i = 0; i < count; i++) {
const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
io.lcd_write_pixel(pixel ? foreground : background);
}
// Move to the next pixel
x++;
if (x >= maxX) {
x = p.x();
y++;
} else {
// transparent bg
int x = p.x();
int y = p.y();
int maxX = x + size.width();
const size_t count = size.width() * size.height();
for (size_t i = 0; i < count; i++) {
const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
if (pixel) {
draw_pixel(ui::Point(x, y), foreground);
}
// move to next px
x++;
if (x >= maxX) {
x = p.x();
y++;
}
}
}
} else { // zoom
// dot to square
for (int y = 0; y < size.height(); y++) {
for (int x = 0; x < size.width(); x++) {
// pos
size_t bit_index = y * size.width() + x;
int byte_index = bit_index >> 3;
int bit_pos = bit_index & 0x7;
// val
const auto pixel = pixels[byte_index] & (1U << bit_pos);
/* ^ the byte_index-th bit AKA current bit
^ current px in current byte*/
if (pixel || background.v != ui::Color::magenta().v) {
fill_rectangle(
{p.x() + x * zoom_level, p.y() + y * zoom_level,
zoom_level, zoom_level},
pixel ? foreground : background);
}
}
}
}
@@ -680,8 +708,9 @@ void ILI9341::draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background) {
draw_bitmap(p, glyph.size(), glyph.pixels(), foreground, background);
const ui::Color background,
uint8_t zoom_level) {
draw_bitmap(p, glyph.size(), glyph.pixels(), foreground, background, zoom_level);
}
void ILI9341::scroll_set_area(
+4 -2
View File
@@ -86,13 +86,15 @@ class ILI9341 {
const ui::Size size,
const uint8_t* const data,
const ui::Color foreground,
const ui::Color background);
const ui::Color background,
uint8_t zoom_level = 1);
void draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background);
const ui::Color background,
uint8_t zoom_level = 1);
/*** Scrolling ***
* Scrolling support is implemented in the ILI9341 driver. Basically a region
+27 -172
View File
@@ -137,9 +137,9 @@ struct ui_config2_t {
bool button_repeat_delay : 1;
bool button_repeat_speed : 1;
bool button_long_press_delay : 1;
bool battery_charge_hint : 1;
uint8_t theme_id;
uint8_t PLACEHOLDER_3;
};
static_assert(sizeof(ui_config2_t) == sizeof(uint32_t));
@@ -480,6 +480,10 @@ void persist() {
} /* namespace cache */
uint32_t get_data_structure_version() {
return data->structure_version;
}
uint32_t pmem_data_word(uint32_t index) {
return backup_ram->pmem_data_word(index);
}
@@ -562,6 +566,10 @@ void set_afsk_space(const int32_t new_value) {
data->afsk_space_freq = afsk_freq_range.clip(new_value);
}
uint32_t get_modem_def_index() {
return data->modem_def_index;
}
int32_t modem_baudrate() {
modem_baudrate_range.reset_if_outside(data->modem_baudrate, modem_baudrate_reset_value);
return data->modem_baudrate;
@@ -571,13 +579,11 @@ void set_modem_baudrate(const int32_t new_value) {
data->modem_baudrate = modem_baudrate_range.clip(new_value);
}
/*
int32_t modem_bw() {
modem_bw_range.reset_if_outside(data->modem_bw, modem_bw_reset_value);
return data->modem_bw;
}
void set_modem_bw(const int32_t new_value) {
/*void set_modem_bw(const int32_t new_value) {
data->modem_bw = modem_bw_range.clip(new_value);
}
*/
@@ -672,10 +678,18 @@ void set_gui_return_icon(bool v) {
data->ui_config.show_gui_return_icon = v ? 1 : 0;
}
bool load_app_settings() {
return data->ui_config.load_app_settings;
}
void set_load_app_settings(bool v) {
data->ui_config.load_app_settings = v ? 1 : 0;
}
bool save_app_settings() {
return data->ui_config.save_app_settings;
}
void set_save_app_settings(bool v) {
data->ui_config.save_app_settings = v ? 1 : 0;
}
@@ -809,6 +823,9 @@ 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);
}
uint64_t get_recon_config() {
return data->recon_config;
}
bool recon_autosave_freqs() {
return check_recon_config_bit(RC_AUTOSAVE_FREQS);
}
@@ -964,6 +981,9 @@ bool ui_button_repeat_speed() {
bool ui_button_long_press_delay() {
return data->ui_config2.button_long_press_delay;
}
bool ui_battery_charge_hint() {
return data->ui_config2.battery_charge_hint;
}
void set_ui_hide_speaker(bool v) {
data->ui_config2.hide_speaker = v;
@@ -1018,6 +1038,9 @@ void set_ui_button_repeat_speed(bool v) {
void set_ui_button_long_press_delay(bool v) {
data->ui_config2.button_long_press_delay = v;
}
void set_ui_battery_charge_hint(bool v) {
data->ui_config2.battery_charge_hint = v;
}
/* Converter */
bool config_converter() {
@@ -1199,173 +1222,5 @@ size_t data_size() {
return sizeof(data_t);
}
// Dump pmem, receiver and transmitter models internals in human readable format
bool debug_dump() {
ui::Painter painter{};
std::string debug_dir = "DEBUG";
std::filesystem::path filename{};
File pmem_dump_file{};
// create new dump file name and DEBUG directory
ensure_directory(debug_dir);
filename = next_filename_matching_pattern(debug_dir + "/DEBUG_DUMP_????.TXT");
if (filename.empty()) {
painter.draw_string({0, 320 - 16}, *ui::Theme::getInstance()->fg_red, "COULD NOT GET DUMP NAME !");
return false;
}
// dump data fo filename
auto error = pmem_dump_file.create(filename);
if (error) {
painter.draw_string({0, 320 - 16}, *ui::Theme::getInstance()->fg_red, "ERROR DUMPING " + filename.filename().string() + " !");
return false;
}
pmem_dump_file.write_line("FW version: " VERSION_STRING);
pmem_dump_file.write_line("Ext APPS version req'd: 0x" + to_string_hex(VERSION_MD5));
pmem_dump_file.write_line("GCC version: " + to_string_dec_int(__GNUC__) + "." + to_string_dec_int(__GNUC_MINOR__) + "." + to_string_dec_int(__GNUC_PATCHLEVEL__));
// firmware checksum
pmem_dump_file.write_line("Firmware calculated checksum: 0x" + to_string_hex(simple_checksum(FLASH_STARTING_ADDRESS, FLASH_ROM_SIZE), 8));
// write persistent memory
pmem_dump_file.write_line("\n[Persistent Memory]");
// full variables
pmem_dump_file.write_line("structure_version: 0x" + to_string_hex(data->structure_version, 8));
pmem_dump_file.write_line("target_frequency: " + to_string_dec_int(data->target_frequency));
pmem_dump_file.write_line("correction_ppb: " + to_string_dec_int(data->correction_ppb));
pmem_dump_file.write_line("modem_def_index: " + to_string_dec_uint(data->modem_def_index));
pmem_dump_file.write_line("serial_format.data_bit: " + to_string_dec_uint(data->serial_format.data_bits));
pmem_dump_file.write_line("serial_format.parity: " + to_string_dec_uint(data->serial_format.parity));
pmem_dump_file.write_line("serial_format.stop_bits: " + to_string_dec_uint(data->serial_format.stop_bits));
pmem_dump_file.write_line("serial_format.bit_order: " + to_string_dec_uint(data->serial_format.bit_order));
pmem_dump_file.write_line("modem_bw: " + to_string_dec_int(data->modem_bw));
pmem_dump_file.write_line("afsk_mark_freq: " + to_string_dec_int(data->afsk_mark_freq));
pmem_dump_file.write_line("afsk_space_freq: " + to_string_dec_int(data->afsk_space_freq));
pmem_dump_file.write_line("modem_baudrate: " + to_string_dec_int(data->modem_baudrate));
pmem_dump_file.write_line("modem_repeat: " + to_string_dec_int(data->modem_repeat));
pmem_dump_file.write_line("pocsag_last_address: " + to_string_dec_uint(data->pocsag_last_address));
pmem_dump_file.write_line("pocsag_ignore_address: " + to_string_dec_uint(data->pocsag_ignore_address));
pmem_dump_file.write_line("tone_mix: " + to_string_dec_uint(data->tone_mix));
pmem_dump_file.write_line("hardware_config: " + to_string_dec_uint(data->hardware_config));
pmem_dump_file.write_line("recon_config: 0x" + to_string_hex(data->recon_config, 16));
pmem_dump_file.write_line("recon_repeat_nb: " + to_string_dec_int(data->recon_repeat_nb));
pmem_dump_file.write_line("recon_repeat_gain: " + to_string_dec_int(data->recon_repeat_gain));
pmem_dump_file.write_line("recon_repeat_delay: " + to_string_dec_int(data->recon_repeat_delay));
pmem_dump_file.write_line("converter: " + to_string_dec_int(data->converter));
pmem_dump_file.write_line("updown_converter: " + to_string_dec_int(data->updown_converter));
pmem_dump_file.write_line("updown_frequency_rx_correction: " + to_string_dec_int(data->updown_frequency_rx_correction));
pmem_dump_file.write_line("updown_frequency_tx_correction: " + to_string_dec_int(data->updown_frequency_tx_correction));
pmem_dump_file.write_line("lcd_inverted_mode: " + to_string_dec_uint(data->lcd_inverted_mode));
// pmem_dump_file.write_line("UNUSED_5: " + to_string_dec_int(data->UNUSED_5));
// pmem_dump_file.write_line("UNUSED_6: " + to_string_dec_int(data->UNUSED_6));
// pmem_dump_file.write_line("UNUSED_7: " + to_string_dec_int(data->UNUSED_7));
pmem_dump_file.write_line("converter_frequency_offset: " + to_string_dec_int(data->converter_frequency_offset));
pmem_dump_file.write_line("frequency_rx_correction: " + to_string_dec_uint(data->frequency_rx_correction));
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));
pmem_dump_file.write_line("fake_brightness_level: " + to_string_dec_uint(data->fake_brightness_level));
pmem_dump_file.write_line("menu_color: 0x" + to_string_hex(data->menu_color.v, 4));
pmem_dump_file.write_line("touchscreen_threshold: " + to_string_dec_uint(data->touchscreen_threshold));
// ui_config bits
const auto backlight_timer = portapack::persistent_memory::config_backlight_timer();
pmem_dump_file.write_line("ui_config clkout_freq: " + to_string_dec_uint(clkout_freq()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_enabled: " + to_string_dec_uint(backlight_timer.timeout_enabled()));
pmem_dump_file.write_line("ui_config backlight_timer.timeout_seconds: " + to_string_dec_uint(backlight_timer.timeout_seconds()));
pmem_dump_file.write_line("ui_config show_gui_return_icon: " + to_string_dec_uint(data->ui_config.show_gui_return_icon));
pmem_dump_file.write_line("ui_config load_app_settings: " + to_string_dec_uint(data->ui_config.load_app_settings));
pmem_dump_file.write_line("ui_config save_app_settings: " + to_string_dec_uint(data->ui_config.save_app_settings));
pmem_dump_file.write_line("ui_config disable_touchscreen: " + to_string_dec_uint(data->ui_config.disable_touchscreen));
pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(data->ui_config.hide_clock));
pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(data->ui_config.clock_show_date));
pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(data->ui_config.clkout_enabled));
pmem_dump_file.write_line("ui_config apply_fake_brightness: " + to_string_dec_uint(data->ui_config.apply_fake_brightness));
pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(data->ui_config.stealth_mode));
pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(data->ui_config.config_login));
pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(data->ui_config.config_splash));
// ui_config2 bits
pmem_dump_file.write_line("ui_config2 hide_speaker: " + to_string_dec_uint(data->ui_config2.hide_speaker));
pmem_dump_file.write_line("ui_config2 hide_converter: " + to_string_dec_uint(data->ui_config2.hide_converter));
pmem_dump_file.write_line("ui_config2 hide_stealth: " + to_string_dec_uint(data->ui_config2.hide_stealth));
pmem_dump_file.write_line("ui_config2 hide_camera: " + to_string_dec_uint(data->ui_config2.hide_camera));
pmem_dump_file.write_line("ui_config2 hide_sleep: " + to_string_dec_uint(data->ui_config2.hide_sleep));
pmem_dump_file.write_line("ui_config2 hide_bias_tee: " + to_string_dec_uint(data->ui_config2.hide_bias_tee));
pmem_dump_file.write_line("ui_config2 hide_clock: " + to_string_dec_uint(data->ui_config2.hide_clock));
pmem_dump_file.write_line("ui_config2 hide_sd_card: " + to_string_dec_uint(data->ui_config2.hide_sd_card));
pmem_dump_file.write_line("ui_config2 hide_mute: " + to_string_dec_uint(data->ui_config2.hide_mute));
pmem_dump_file.write_line("ui_config2 hide_fake_brightness: " + to_string_dec_uint(data->ui_config2.hide_fake_brightness));
pmem_dump_file.write_line("ui_config2 hide_battery_icon: " + to_string_dec_uint(data->ui_config2.hide_battery_icon));
pmem_dump_file.write_line("ui_config2 hide_numeric_battery: " + to_string_dec_uint(data->ui_config2.hide_numeric_battery));
pmem_dump_file.write_line("ui_config2 theme_id: " + to_string_dec_uint(data->ui_config2.theme_id));
pmem_dump_file.write_line("ui_config2 override_batt_calc: " + to_string_dec_uint(data->ui_config2.override_batt_calc));
pmem_dump_file.write_line("ui_config2 button_repeat_delay: " + to_string_dec_uint(data->ui_config2.button_repeat_delay));
pmem_dump_file.write_line("ui_config2 button_repeat_speed: " + to_string_dec_uint(data->ui_config2.button_repeat_speed));
pmem_dump_file.write_line("ui_config2 button_long_press_delay: " + to_string_dec_uint(data->ui_config2.button_long_press_delay));
// misc_config bits
pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute()));
pmem_dump_file.write_line("misc_config config_speaker_disable: " + to_string_dec_int(config_speaker_disable()));
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]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(receiver_model.target_frequency()));
pmem_dump_file.write_line("frequency_step: " + to_string_dec_uint(receiver_model.frequency_step()));
pmem_dump_file.write_line("lna: " + to_string_dec_int(receiver_model.lna()));
pmem_dump_file.write_line("vga: " + to_string_dec_int(receiver_model.vga()));
pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(receiver_model.rf_amp()));
pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(receiver_model.baseband_bandwidth()));
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(receiver_model.sampling_rate()));
switch (receiver_model.modulation()) {
case ReceiverModel::Mode::AMAudio:
pmem_dump_file.write_line("modulation: Mode::AMAudio");
break;
case ReceiverModel::Mode::NarrowbandFMAudio:
pmem_dump_file.write_line("modulation: Mode::NarrowbandFMAudio");
break;
case ReceiverModel::Mode::WidebandFMAudio:
pmem_dump_file.write_line("modulation: Mode::WidebandFMAudio");
break;
case ReceiverModel::Mode::SpectrumAnalysis:
pmem_dump_file.write_line("modulation: Mode::SpectrumAnalysis");
break;
case ReceiverModel::Mode::Capture:
pmem_dump_file.write_line("modulation: Mode::Capture");
break;
case ReceiverModel::Mode::AMAudioFMApt:
pmem_dump_file.write_line("modulation: Mode::AMAudioFMApt");
break;
default:
pmem_dump_file.write_line("modulation: !!unknown mode!!");
break;
}
pmem_dump_file.write_line("headphone_volume.centibel: " + to_string_dec_int(receiver_model.headphone_volume().centibel()));
pmem_dump_file.write_line("normalized_headphone_volume: " + to_string_dec_uint(receiver_model.normalized_headphone_volume()));
pmem_dump_file.write_line("am_configuration: " + to_string_dec_uint(receiver_model.am_configuration()));
pmem_dump_file.write_line("nbfm_configuration: " + to_string_dec_uint(receiver_model.nbfm_configuration()));
pmem_dump_file.write_line("wfm_configuration: " + to_string_dec_uint(receiver_model.wfm_configuration()));
// transmitter_model
pmem_dump_file.write_line("\n[Transmitter Model]");
pmem_dump_file.write_line("target_frequency: " + to_string_dec_uint(transmitter_model.target_frequency()));
pmem_dump_file.write_line("rf_amp: " + to_string_dec_int(transmitter_model.rf_amp()));
pmem_dump_file.write_line("baseband_bandwidth: " + to_string_dec_uint(transmitter_model.baseband_bandwidth()));
pmem_dump_file.write_line("sampling_rate: " + to_string_dec_uint(transmitter_model.sampling_rate()));
pmem_dump_file.write_line("tx_gain: " + to_string_dec_int(transmitter_model.tx_gain()));
pmem_dump_file.write_line("channel_bandwidth: " + to_string_dec_uint(transmitter_model.channel_bandwidth()));
// on screen information
painter.draw_string({0, 320 - 16}, *ui::Theme::getInstance()->fg_green, filename.filename().string() + " DUMPED !");
return true;
}
} /* namespace persistent_memory */
} /* namespace portapack */
@@ -183,9 +183,13 @@ void set_afsk_mark(const int32_t new_value);
int32_t afsk_space_freq();
void set_afsk_space(const int32_t new_value);
uint32_t get_modem_def_index();
int32_t modem_baudrate();
void set_modem_baudrate(const int32_t new_value);
int32_t modem_bw();
uint8_t modem_repeat();
void set_modem_repeat(const uint32_t new_value);
@@ -214,7 +218,9 @@ backlight_config_t config_backlight_timer();
bool disable_touchscreen();
void set_gui_return_icon(bool v);
bool load_app_settings();
void set_load_app_settings(bool v);
bool save_app_settings();
void set_save_app_settings(bool v);
void set_config_disable_external_tcxo(bool v);
void set_config_sdcard_high_speed_io(bool v, bool save);
@@ -290,6 +296,7 @@ Color menu_color();
void set_menu_color(Color v);
/* Recon app */
uint64_t get_recon_config();
bool recon_autosave_freqs();
bool recon_autostart_recon();
bool recon_continuous();
@@ -343,6 +350,8 @@ bool ui_override_batt_calc();
bool ui_button_repeat_delay();
bool ui_button_repeat_speed();
bool ui_button_long_press_delay();
bool ui_battery_charge_hint();
void set_ui_hide_speaker(bool v);
void set_ui_hide_mute(bool v);
void set_ui_hide_converter(bool v);
@@ -360,20 +369,20 @@ void set_ui_override_batt_calc(bool v);
void set_ui_button_repeat_delay(bool v);
void set_ui_button_repeat_speed(bool v);
void set_ui_button_long_press_delay(bool v);
void set_ui_battery_charge_hint(bool v);
// sd persisting settings
bool should_use_sdcard_for_pmem();
int save_persistent_settings_to_file();
int load_persistent_settings_from_file();
uint32_t get_data_structure_version();
uint32_t pmem_data_word(uint32_t index);
uint32_t pmem_stored_checksum(void);
uint32_t pmem_calculated_checksum(void);
size_t data_size();
bool debug_dump();
} /* namespace persistent_memory */
} /* namespace portapack */
+3 -25
View File
@@ -36,34 +36,12 @@ Style Style::invert() const {
.foreground = background};
}
int Painter::draw_char(Point p, const Style& style, char c, uint8_t zoom_factor) {
int Painter::draw_char(Point p, const Style& style, char c, uint8_t zoom_level) {
const auto glyph = style.font.glyph(c);
if (zoom_factor <= 1) {
display.draw_glyph(p, glyph, style.foreground, style.background);
} else {
// dot to square
const uint8_t* pixels = glyph.pixels();
for (int y = 0; y < glyph.h(); y++) { // each line
for (int x = 0; x < glyph.w(); x++) { // each clum
// pos
int byte_index = (y * glyph.w() + x) / 8;
int bit_pos = (y * glyph.w() + x) % 8;
display.draw_glyph(p, glyph, style.foreground, style.background, zoom_level);
// fill
Color pixel_color = ((pixels[byte_index] & (1 << bit_pos)) != 0) ? style.foreground : style.background;
/* ^ true: fg, false: bg
^ the byte_index-th bit AKA current bit
^ current px in current byte */
display.fill_rectangle(
{p.x() + x * zoom_factor, p.y() + y * zoom_factor,
zoom_factor, zoom_factor},
pixel_color);
}
}
}
return glyph.advance().x() * zoom_factor;
return glyph.advance().x() * zoom_level;
}
int Painter::draw_string(Point p, const Style& style, std::string_view text) {
+1 -1
View File
@@ -1136,7 +1136,7 @@ void ButtonWithEncoder::paint(Painter& painter) {
const Style paint_style = {style().font, bg, fg};
painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Theme::getInstance()->fg_light->foreground);
painter.draw_rectangle({r.location(), {r.size().width(), 1}}, Theme::getInstance()->bg_light->background);
painter.draw_rectangle({r.location().x(), r.location().y() + r.size().height() - 1, r.size().width(), 1}, Theme::getInstance()->bg_dark->background);
painter.draw_rectangle({r.location().x() + r.size().width() - 1, r.location().y(), 1, r.size().height()}, Theme::getInstance()->bg_dark->background);
+1
View File
@@ -0,0 +1 @@
bitmap.hpp
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
# Copyright (C) 2016 Furrtek
#
# 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.
#
import sys
import struct
from PIL import Image
from os import listdir
from os import path
from os import makedirs
usage_message = f"""
1BPP PortaPack bitmap.hpp generator
Usage: {sys.argv[0]} <directory>
"""
if len(sys.argv) < 2:
print(usage_message)
sys.exit(-1)
graphics_path = path.join(sys.argv[1], '')
hex_output_dir = path.join(graphics_path, 'hex_files')
# Create hex output directory if it doesn't exist
if not path.exists(hex_output_dir):
makedirs(hex_output_dir)
def convert_png(file):
c = 0
data = 0
rgb_im = Image.open(file).convert('RGBA')
if rgb_im.size[0] % 8 or rgb_im.size[1] % 8:
print((file + ": Size is not a multiple of 8. Image is not included in bitmap.hpp."))
sys.exit(-1)
name = path.basename(file).split(".")[0].lower();
# Prepare data for both hpp and hex file
hpp_lines = []
hex_data = bytearray()
for i in range(rgb_im.size[1]):
for j in range(rgb_im.size[0]):
r, g, b, a = rgb_im.getpixel((j, i))
data >>= 1
if r > 127 and g > 127 and b > 127 and a > 127:
data += 128
if j % 8 == 7:
hpp_lines.append(" 0x%0.2X,\n" % data)
hex_data.append(data)
data = 0
# Write to hpp file
f.write("static constexpr uint8_t bitmap_" + name + "_data[] = {\n")
f.writelines(hpp_lines)
f.write("};\n")
f.write("static constexpr Bitmap bitmap_" + name + " {\n")
f.write(" {" + str(rgb_im.size[0]) + ", " + str(rgb_im.size[1]) + "},\n bitmap_" + name + "_data};\n\n")
# Write to hex file
hex_filename = path.join(hex_output_dir, name + ".hex")
with open(hex_filename, 'wb') as hex_file:
hex_file.write(hex_data)
return
count = 0
f = open('bitmap.hpp', 'w')
f.write("/*\n"
" * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.\n"
" * Copyright (C) 2016 Furrtek\n"
" *\n"
" * This file is part of PortaPack.\n"
" *\n"
" * This program is free software; you can redistribute it and/or modify\n"
" * it under the terms of the GNU General Public License as published by\n"
" * the Free Software Foundation; either version 2, or (at your option)\n"
" * any later version.\n"
" *\n"
" * This program is distributed in the hope that it will be useful,\n"
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" * GNU General Public License for more details.\n"
" *\n"
" * You should have received a copy of the GNU General Public License\n"
" * along with this program; see the file COPYING. If not, write to\n"
" * the Free Software Foundation, Inc., 51 Franklin Street,\n"
" * Boston, MA 02110-1301, USA.\n"
" */\n\n"
"// This file was generated by make_bitmap.py\n\n"
"#ifndef __BITMAP_HPP__\n"
"#define __BITMAP_HPP__\n\n"
"#include \"ui.hpp\"\n\n"
"namespace ui {\n\n")
for file in listdir(graphics_path):
if file.endswith(".png") and path.isfile(graphics_path + file):
convert_png(graphics_path + file)
count += 1
f.write("} /* namespace ui */\n\n")
f.write("#endif/*__BITMAP_HPP__*/\n")
print(("Converted " + str(count) + " files"))
@@ -120,10 +120,10 @@ def main():
if validate_memory_regions(regions):
print("external app addr seems correct, pass")
else:
print("\nWARENING: It seems you are having incorrect external app addresses.")
print("\nWARNING: It seems you are having incorrect external app addresses.")
except Exception as e:
print(f"err: {e}")
if __name__ == "__main__":
main()
main()
@@ -137,7 +137,12 @@ def get_pp_device_linux():
parts = clean_line.split()
if len(parts) >= 2 and SDCARD_LABEL in parts[1]: # checker
print("found pp sd:")
device_path = parts[0]
#remove `- in it
device_path = device_path.replace('-', '')
device_path = device_path.replace('`', '')
print(device_path)
# if path valid
if not os.path.exists(device_path):
continue
+1 -1
View File
@@ -199,7 +199,7 @@ try:
if validate_memory_regions(regions):
print("external app addr seems correct, pass")
else:
print("\nWARENING: It seems you are having incorrect external app addresses.")
print("\nWARNING: It seems you are having incorrect external app addresses.")
except Exception as e:
print(f"err: {e}")
+5
View File
@@ -0,0 +1,5 @@
## Brief description what you did
## Checklist
- [ ] Kept changes minimal and limited to necessary files
- [ ] Verified functionality remains intact and code compiles
-25
View File
@@ -1,25 +0,0 @@
# Description: WEather FAX list
# Author: gullradriel
# Deutscher Wetterdienst (DWD) - Offenbach, Germany
# Surface analysis: 04:30,10:50,16:36,22:00 UTC
f=3855000,m=AMFM,bw=USB+FM,d=DWD DDH3 Analysis
# Surface analysis, forecasts, warnings (continuous)
f=7880000,m=AMFM,bw=USB+FM,d=DWD DDK3 Forecasts
# Surface analysis & wave height (continuous)
f=13882500,m=AMFM,bw=USB+FM,d=DWD DDK6 Waves
# Royal Navy (Northwood) - United Kingdom
# Surface/Wave charts every 6 hrs
f=2618500,m=AMFM,bw=USB+FM,d=Northwood 2.6MHz WX
f=4610000,m=AMFM,bw=USB+FM,d=Northwood 4.6MHz WX
f=8040000,m=AMFM,bw=USB+FM,d=Northwood 8.0MHz WX
f=11086500,m=AMFM,bw=USB+FM,d=Northwood 11MHz WX
# United States Coast Guard (USCG) - Boston/NMF
# Atlantic Analysis: 03:00,09:00,15:00,21:00 UTC
f=6340500,m=AMFM,bw=USB+FM,d=USCG 6.3MHz Atlantic
# Forecasts & Hurricane Warnings (continuous updates)
f=9110000,m=AMFM,bw=USB+FM,d=USCG 9.1MHz WX Warn
# Extended Marine Forecasts (continuous updates)
f=12750000,m=AMFM,bw=USB+FM,d=USCG 12.7MHz Marine
+51
View File
@@ -0,0 +1,51 @@
# Description: WEather FAX list, part 1
# See https://weatherfax.com/stations
# Australia
f=2628000,m=AMFM,bw=USB+FM,d=VMC Charleville
f=5100000,m=AMFM,bw=USB+FM,d=VMC Charleville
f=11030000,m=AMFM,bw=USB+FM,d=VMC Charleville
f=13920000,m=AMFM,bw=USB+FM,d=VMC Charleville
f=20469000,m=AMFM,bw=USB+FM,d=VMC Charleville
f=5755000,m=AMFM,bw=USB+FM,d=VMW Wiluna
f=7535000,m=AMFM,bw=USB+FM,d=VMW Wiluna
f=10555000,m=AMFM,bw=USB+FM,d=VMW Wiluna
f=15615000,m=AMFM,bw=USB+FM,d=VMW Wiluna
f=18060000,m=AMFM,bw=USB+FM,d=VMW Wiluna
# Canada
f=4416000,m=AMFM,bw=USB+FM,d=VCO Sydney NS
f=6915100,m=AMFM,bw=USB+FM,d=VCO Sydney NS
f=4292000,m=AMFM,bw=USB+FM,d=VFA Inuvik
f=8456000,m=AMFM,bw=USB+FM,d=VFA Inuvik
f=3253000,m=AMFM,bw=USB+FM,d=VFF Iqaluit/VFR Resolute
f=7710000,m=AMFM,bw=USB+FM,d=VFF Iqaluit/VFR Resolute
# Chile
f=4322000,m=AMFM,bw=USB+FM,d=CBM Punta Arenas
f=8696000,m=AMFM,bw=USB+FM,d=CBM Punta Arenas
f=4228000,m=AMFM,bw=USB+FM,d=CBV Vaparaiso
f=8677000,m=AMFM,bw=USB+FM,d=CBV Vaparaiso
f=17146400,m=AMFM,bw=USB+FM,d=CBV Vaparaiso
# China
f=4170000,m=AMFM,bw=USB+FM,d=XSG Shanghai
f=8302000,m=AMFM,bw=USB+FM,d=XSG Shanghai
f=12382000,m=AMFM,bw=USB+FM,d=XSG Shanghai
f=16559000,m=AMFM,bw=USB+FM,d=XSG Shanghai
f=4199800,m=AMFM,bw=USB+FM,d=XSQ Guangzhou
f=8412500,m=AMFM,bw=USB+FM,d=XSQ Guangzhou
f=12629300,m=AMFM,bw=USB+FM,d=XSQ Guangzhou
f=16826300,m=AMFM,bw=USB+FM,d=XSQ Guangzhou
# Germany - Deutscher Wetterdienst (DWD) - Offenbach
# Surface analysis: 04:30,10:50,16:36,22:00 UTC
f=3855000,m=AMFM,bw=USB+FM,d=DWD DDH3 Analysis
# Surface analysis, forecasts, warnings (continuous)
f=7880000,m=AMFM,bw=USB+FM,d=DWD DDK3 Forecasts
# Surface analysis & wave height (continuous)
f=13882500,m=AMFM,bw=USB+FM,d=DWD DDK6 Waves
# Greece
f=4482900,m=AMFM,bw=USB+FM,d=SVJ4 Athens
f=8106900,m=AMFM,bw=USB+FM,d=SVJ4 Athens
+58
View File
@@ -0,0 +1,58 @@
# Description: WEather FAX list, part 2
# See https://weatherfax.com/stations
# Japan
f=3622500,m=AMFM,bw=USB+FM,d=JMH Tokyo
f=7795000,m=AMFM,bw=USB+FM,d=JMH Tokyo
f=13988500,m=AMFM,bw=USB+FM,d=JMH Tokyo
f=16971000,m=AMFM,bw=USB+FM,d=JJC Tokyo
f=4274000,m=AMFM,bw=USB+FM,d=JFX Kagoshima
f=8658000,m=AMFM,bw=USB+FM,d=JFX Kagoshima
f=13074000,m=AMFM,bw=USB+FM,d=JFX Kagoshima
f=16907500,m=AMFM,bw=USB+FM,d=JFX Kagoshima
f=22559600,m=AMFM,bw=USB+FM,d=JFX Kagoshima
# Korea
f=3585000,m=AMFM,bw=USB+FM,d=HLL2 Seoul
f=5857500,m=AMFM,bw=USB+FM,d=HLL2 Seoul
f=7433500,m=AMFM,bw=USB+FM,d=HLL2 Seoul
f=9165000,m=AMFM,bw=USB+FM,d=HLL2 Seoul
f=13570000,m=AMFM,bw=USB+FM,d=HLL2 Seoul
# Russia
f=6328500,m=AMFM,bw=USB+FM,d=UDK2 Murmansk
f=8444000,m=AMFM,bw=USB+FM,d=UDK2 Murmansk
f=2640000,m=AMFM,bw=USB+FM,d=St Petersburg RU
f=4212000,m=AMFM,bw=USB+FM,d=St Petersburg RU
f=6456900,m=AMFM,bw=USB+FM,d=Vanino RU
# Thailand
f=7396900,m=AMFM,bw=USB+FM,d=HSW64 Bangkok
# United Kingdom - Royal Navy
# Surface/Wave charts every 6 hrs
f=2618500,m=AMFM,bw=USB+FM,d=GYA Northwood
f=4610000,m=AMFM,bw=USB+FM,d=GYA Northwood
f=8040000,m=AMFM,bw=USB+FM,d=GYA Northwood
f=11086500,m=AMFM,bw=USB+FM,d=GYA Northwood
# United States - Coast Guard (USCG)
f=4346000,m=AMFM,bw=USB+FM,d=NMC Point Reyes
f=8682000,m=AMFM,bw=USB+FM,d=NMC Point Reyes
f=12786000,m=AMFM,bw=USB+FM,d=NMC Point Reyes
f=17151200,m=AMFM,bw=USB+FM,d=NMC Point Reyes
f=22527000,m=AMFM,bw=USB+FM,d=NMC Point Reyes
f=4235000,m=AMFM,bw=USB+FM,d=NMF Boston
f=6340500,m=AMFM,bw=USB+FM,d=NMF Boston Atlantic
f=9110000,m=AMFM,bw=USB+FM,d=NMF Boston WX Warn
f=12750000,m=AMFM,bw=USB+FM,d=NMF Boston Marine
f=4317900,m=AMFM,bw=USB+FM,d=NMG New Orleans
f=8503900,m=AMFM,bw=USB+FM,d=NMG New Orleans
f=12789900,m=AMFM,bw=USB+FM,d=NMG New Orleans
f=17146400,m=AMFM,bw=USB+FM,d=NMG New Orleans
f=4298000,m=AMFM,bw=USB+FM,d=NOJ Kodiak
f=8459000,m=AMFM,bw=USB+FM,d=NOJ Kodiak
f=12412500,m=AMFM,bw=USB+FM,d=NOJ Kodiak
f=9982500,m=AMFM,bw=USB+FM,d=KVM70 Honolulu
f=11090000,m=AMFM,bw=USB+FM,d=KVM70 Honolulu
f=16135000,m=AMFM,bw=USB+FM,d=KVM70 Honolulu