Compare commits

...

58 Commits

Author SHA1 Message Date
Mark Thompson 1fbfdbccf8 Remove unused text_info widget (#1955) 2024-03-08 01:29:13 +08:00
Totoo 2648f18b12 External sensor tester app (#1949)
* added tilt
* added extsensors app
* added icon
* Added EnvironmentData to ExtSensor app and message.hpp
* Added gotenv command
2024-03-07 17:22:24 +01:00
Mark Thompson 908c0e2cd5 Fix compiler warning (#1952) 2024-03-07 17:18:08 +01:00
Mark Thompson 4f3530db5e Update FPV_ANALOG.TXT (#1951)
* Include FPV in freq description

* Added comment referencing source of this data
2024-03-08 00:00:53 +08:00
not tre mann 73137891c4 change sun bitmap to make it more like a sun (#1946) 2024-03-07 07:50:49 +01:00
not tre mann c28087ac44 cheat code protect in pacman app (#1945) 2024-03-07 07:49:17 +01:00
Totoo 9e9dd3a521 Dynamic usb buffer fill for screenframeshort (#1935)
* fully fill usb serial buffer
* Update usb_serial_shell.cpp
* Added a comment, to trigger wf
2024-03-07 07:42:58 +01:00
Dima Danylevskyi 3bf689f339 Add FPV analog frequenies to FREQMAN (#1940) 2024-03-07 07:37:41 +01:00
Erwin Ried 86c326ef12 Update README.md (#1937)
Adding a warning
2024-02-26 17:50:11 +01:00
jLynx 5ae97d47f1 Fixed existing dir check (#1933) 2024-02-25 08:28:44 +01:00
Erwin Ried 762512b7dc Rename problem-upgrading-the-firmware.md to 03_problem-upgrading-the-firmware.md 2024-02-23 14:13:54 +01:00
Erwin Ried 9c848a6215 Update config.yml 2024-02-23 14:13:23 +01:00
Erwin Ried 9c86e15ddb Rename feature_request.yml to 02_feature_request.yml 2024-02-23 14:12:20 +01:00
Erwin Ried 57ccdb0044 Update and rename feature_request.md to feature_request.yml 2024-02-23 14:11:13 +01:00
Erwin Ried 1172175cc8 Rename bug_report.md to 01_bug_report.yml 2024-02-23 14:06:04 +01:00
Erwin Ried 9ed8ad5903 Create config.yml 2024-02-23 14:04:52 +01:00
Erwin Ried e4da8b979e Update bug_report.md (#1929) 2024-02-23 14:02:11 +01:00
Erwin Ried 4b83fd8a40 Updating the videos from people about hackrf (#1918)
The latest series from sasquash looks promising to engage beginners :) also will do some tracking with grabify to check engagement
2024-02-19 19:30:14 +08:00
Mark Thompson cd80da58d8 Improved flash image validation (#1916) 2024-02-18 19:02:42 +01:00
Mark Thompson a1f7010e08 Optimized fake brightness code (#1915) 2024-02-17 18:44:06 -06:00
Noah Axon 3499d2fa75 Fix Recon Modulation/Bandwidth presets (#1913) 2024-02-17 19:24:11 +01:00
notComposer 948e039574 fix shift back in screenshot and mayhem hub (#1910)
* fix_shift_back

* clean up

* gitignore

* remove the workaround in notpad cuz it's been fixed in this PR

* format

* add credit for mark

* 2024
2024-02-18 00:44:31 +08:00
Bernd Herzog 27dc37713b added crc32 command to usb shell (#1911) 2024-02-17 10:38:09 +01:00
jLynx ed834e3553 V2.0.0 setup (#1908)
* Update past_version.txt

* Update version.txt
2024-02-16 19:14:46 +00:00
Mark Thompson ce08d93ae2 Fix Pacman pause button glitches (again) (#1906) 2024-02-16 07:50:50 +01:00
Mark Thompson 13fd1b1f3b Support for configurable Menu Color & scrolling fix (#1905)
* Support for Configurable Menu Color Scheme
* Limit min value to 8 so doesn't get reset to default
* Increased max encoder rate multiplier value to 15
* Fixed menu scrolling issue
2024-02-16 07:19:43 +01:00
Mark Thompson d04c781ada Added Reboot app to Debug menu (#1904) 2024-02-16 07:18:33 +01:00
Mark Thompson 24605777a6 Show on_encoder delta in Buttons Test app (#1903) 2024-02-15 21:33:46 +01:00
Mark Thompson b5ac792853 Add color to position info lines in Notepad (#1902) 2024-02-15 18:12:40 +01:00
Mark Thompson 44c319dcc6 Refresh status bar after Pmem Reset (#1899) 2024-02-15 15:00:25 +01:00
Mark Thompson a442971b81 Eliminate unneeded screen flashing when scrolling menu (#1900) 2024-02-15 14:59:30 +01:00
Mark Thompson 8b5adb6bc1 Treat encoder rate multiplier value of 0 in pmem the same as 1 (#1898)
* Double-check encoder rate multiplier is not 0

* Eliminated redundant check in pmem init()
2024-02-15 07:05:05 +01:00
Bernd Herzog c3add0ce84 Cpld autodetect & boot splash screen (#1888)
* added delayed error message when hackrf cpld initialization fails

* refactoring

* implemented portapack cpld autodetection

* refactoring

* fixed valid config range

* added lcd fast setup

* added boot splash screen

* added one frame delay to remove flickering

* fixed config persistence
2024-02-14 23:17:33 +01:00
Mark Thompson 8725b01995 Fixed Pacman pause button (#1894) 2024-02-14 14:43:31 -06:00
E.T 936e8279f9 Add lto flag only to "internal" source files (#1895) 2024-02-14 13:54:20 -06:00
Mark Thompson 6193023c8f Fixed Pacman global object initialization (#1891) 2024-02-14 06:02:27 +01:00
Mark Thompson 1800939833 Fixed Tetris by eliminating some classes (#1890) 2024-02-13 20:54:40 +01:00
Mark Thompson 2f48fc2ef9 Disable LTO for external apps (#1886)
* Disable lto for external apps only

* Modified "shared external code" checks
2024-02-13 10:11:54 -06:00
Bernd Herzog 918ec0574f added delayed error message when hackrf cpld initialization fails (#1887)
* added delayed error message when hackrf cpld initialization fails

* refactoring
2024-02-13 13:06:47 +01:00
Mark Thompson 1139b22141 Fix compile error (#1884) 2024-02-12 19:04:48 +01:00
Brumi-2021 7598c25fc8 Solves random USB/LSB mode in SSB Mic App (H1R1). (#1882)
* Solves random USB/LSB mode in SSB Mic App (H1R1).

* format
2024-02-11 23:16:29 +01:00
Mark Thompson 0f6a9277a8 Warning for shared external code during build (#1881) 2024-02-11 21:25:00 +01:00
Mark Thompson 6a8650d484 Update Copyright in comment blocks (#1878) 2024-02-10 16:56:50 +01:00
Mark Thompson 46d9e02684 Encoder rotation rate multiplier support (#1876) 2024-02-10 09:32:03 +01:00
Mark Thompson 367479d163 Just shift menu icons up 1 row when hit bottom (#1874) 2024-02-10 09:21:35 +01:00
Mark Thompson bbbf5a37c8 Add progress bar to Soundboard app (#1875)
* Add progress bar to Soundboard app

* Clang
2024-02-10 09:04:00 +08:00
Mark Thompson b2ad1fa979 Cycle through brightness levels when icon selected (#1873) 2024-02-09 09:16:55 -06:00
Mark Thompson 998be5ba09 Set fake brightness to 50% default if never configured in Settings (#1871) 2024-02-09 18:36:02 +08:00
theHallwayThatBringMePassion 9e8d279298 fix double darken (#1866) 2024-02-08 18:39:57 +01:00
E.T fd03bb800c Brightness settings fixes 2.0 (#1870)
* Format

* Fix startup crash 🙈

* Revert "Revert "Brightness settings fixes" (#1865)"

Had to rebase then revert the revert to make git recognise and merge the change :)

This reverts commit b7e5bedf4b.

# Conflicts:
#	firmware/application/ui_navigation.cpp

* Add zxkmm to header too
2024-02-08 18:28:49 +01:00
Mark Thompson f80c28cde7 Rename playlist.ini to replay.ini to match app (#1864) 2024-02-08 11:34:40 +01:00
theHallwayThatBringMePassion b7e5bedf4b Revert "Brightness settings fixes" (#1865)
This reverts commit 994e426d1e.
2024-02-08 10:09:00 +08:00
E.T 994e426d1e Brightness settings fixes (#1863)
* Brightness settings fixes

- Statusbar toggle now updated when changing in settings page
- Annoying message boxes removed
- SystemView (aka whole screen) is now refreshed after toggling from status

* Format
2024-02-07 17:52:12 -06:00
Mark Thompson c5bf0d94f9 Skip over INFO chunk in WAV files (#1862) 2024-02-07 21:37:49 +01:00
Mark Thompson 8ad9ada015 Functionally revert PR #1837 (#1861) 2024-02-07 14:07:21 -06:00
Mark Thompson e854261124 WAV viewer tweaks (#1854) 2024-02-07 09:15:46 +01:00
theHallwayThatBringMePassion 0370b4eb55 fake brightness adjust (#1845)
* temp

* temp - 1

* next step note

* fix circuit dependency (to fix:can't read p.mem)

* fix circuit dependency (to fix:can't read p.mem)

* notes

* bitmap

* bitmap

* remove my stupid forward declearation

* clean up

* clean up

* level control

* clean up

* clean up

* clean up

* clean up

* format

* format

* format

* format

* format

* fix for comment advices

* fix for comment advices

* fix display issue in notepad app

* slightly increase performance...

* temp for grey_scale and high_constrast

* format

* note for cache implement

* fix for comment request

* fix for comment request
2024-02-07 16:07:30 +08:00
Matias Fernandez 5eef5b4e31 Rename Marine VHF freqman file to make more explicit what is the file about when you are browsing the files in the scanner app (#1858) 2024-02-07 00:08:37 -06:00
117 changed files with 2070 additions and 526 deletions
+48
View File
@@ -0,0 +1,48 @@
name: Bug report
description: File a bug reports regarding the firmware.
labels: ['bug']
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Mayhem firmware.
Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases
- type: textarea
id: description
attributes:
label: Describe the bug.
description: "A clear and concise description of what the bug is."
validations:
required: true
- type: textarea
id: repro
attributes:
label: Reproduction
description: "How can this bug be reproduced?"
placeholder: |
1. Switch on...
2. Press button '....'
3. Wait for the end of the universe
4. It burns
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: "A clear and concise description of what you expected to happen"
placeholder: |
1. Generates file on...
2. I get a cheeseburger...
validations:
required: true
- type: input
id: target
attributes:
label: Environment/versions
description: Specify extra details about versions and environments affected
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.
@@ -0,0 +1,24 @@
name: Feature Request
description: For feature requests regarding the firmware.
labels: ['feature request']
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions.
Please try the latest nightly release before submitting this, make sure it has not been implemented already. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases
- type: textarea
id: proposal
attributes:
label: "Description of the feature you're suggesting."
description: |
Please describe your feature request in as many details as possible.
- Describe what it should do.
- Note whether it is to extend existing functionality or introduce new functionality.
validations:
required: true
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.
-35
View File
@@ -1,35 +0,0 @@
---
name: Bug report
about: Create a report to help us improve the software
title: ''
labels: bug
assignees: ''
---
----
(Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/portapack-mayhem/mayhem-firmware/releases)
----
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Tap on '....'
3.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Affected versions**
Please write any difference related with the Expected behavior, on the following versions:
* Latest Stable release:
* Latest Nightly release:
* Previous working release:
**Additional**
If the bug is difficult to explain, additionally to the text please include images and videos.
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Need more help?
url: https://discord.com/invite/tuwVMv3
about: For any question that does not fit as an issue, check our discord.
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen. Remember that adding stuff is always possible, but time is a limited resource for everyone. Check the wiki for more information how to compile the firmware and try to explore modifying the code yourself.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional**
If the suggestion is difficult to explain, additionally to the text please include images and videos.
+1 -1
View File
@@ -1 +1 @@
v1.9.0
v1.9.1
+1 -1
View File
@@ -1 +1 @@
v1.9.1
v2.0.0
+9 -2
View File
@@ -55,7 +55,7 @@ CMakeFiles/
# Debugging
.gdbinit*
# Editor/IDE files
# Editor/ IDE files
*.sublime-project
*.sublime-workspace
.vscode
@@ -68,8 +68,15 @@ CMakeFiles/
.DS_Store
/firmware/CMakeCache.txt
# Python env
# Python env/ venv and cache
env/
venv/
**/__pycache__/
*.pyc
# Other
*.bak
# generated bitmap arr file
# TODO: generate bitmap during build, since we use python during build anyway, lemme know if this is a bad idea @zxkmm
/firmware/tools/bitmap.hpp
+10 -5
View File
@@ -1,5 +1,10 @@
> [!IMPORTANT]
> this repository **has just been moved** from my personal GitHub [eried/portapack-mayhem](https://github.com/eried/portapack-mayhem) to an organization: [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware). Please keep this in mind to **update your links** accordingly.
> [!WARNING]
> Recently, we have become aware of certain individuals distributing prepackaged packages of Mayhem for a fee, and we want to bring this to your attention to ensure the integrity and security of our project.
>
> We would like to clarify that none of the contributors to Mayhem receive any monetary compensation for their efforts. All the work put into this project is driven by passion and hobby, and we are committed to providing the community with an open-source solution that remains free of charge.
>
> __IF YOU'VE PAID FOR MAYHEM OR ANY PREPACKAGED PACKAGES, YOU'RE BEING SCAMMED.__ Seek a refund from your card company and report the issue immediately.
> The only legitimate link leading to our repositories is the organization [portapack-mayhem](https://github.com/portapack-mayhem/mayhem-firmware). Please ensure that any download or access to our software is done exclusively through these trusted sources.
# PortaPack Mayhem
@@ -13,11 +18,11 @@ This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmw
# What is this?
If you are new to *HackRF+PortaPack+Mayhem*, check this video:
If you are new to *HackRF+PortaPack+Mayhem*, check these:
[![Beginner's Guide To The HackRF & Portapak With Mayhem](https://img.youtube.com/vi/H-bqdWfbhpg/0.jpg)](https://www.youtube.com/watch?v=H-bqdWfbhpg)
[<img alt="HackRF 101 : Everything You Need to Know to Get Started!" src="https://img.youtube.com/vi/xGR_PMD9LeU/maxresdefault.jpg" width="512">](https://grabify.link/C0J6ZR)
For people familiar with the [Flipper Zero](https://github.com/flipperdevices/flipperzero-firmware), this one might be interesting:<br>[What is the HackRF One Portapack H2+?](https://www.youtube.com/watch?v=alrFbY5vxt4)
[<img alt="Beginner's Guide To The HackRF & Portapak With Mayhem" src="https://img.youtube.com/vi/H-bqdWfbhpg/maxresdefault.jpg" width="254">](https://grabify.link/5MU2VH) [<img alt="What is the HackRF One Portapack H2+?" src="https://img.youtube.com/vi/alrFbY5vxt4/maxresdefault.jpg" width="254">](https://grabify.link/9UZGEW)
# Frequently Asked Questions
+8 -6
View File
@@ -44,7 +44,7 @@ if(cpp20_supported)
else()
set(USE_CPPOPT "-std=c++17")
endif()
set(USE_CPPOPT "${USE_CPPOPT} -flto -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
set(USE_CPPOPT "${USE_CPPOPT} -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized -Wno-volatile")
# Enable this if you want the linker to remove unused code and data
set(USE_LINK_GC yes)
@@ -52,7 +52,7 @@ set(USE_LINK_GC yes)
# Linker extra options here.
set(USE_LDOPT)
# Enable this if you want link time optimizations (LTO)
# Enable this if you want link time optimizations (LTO) - this flag affects chibios only
set(USE_LTO no)
# If enabled, this option allows to compile the application in THUMB mode.
@@ -293,7 +293,7 @@ set(CPPSRC
# apps/ui_jammer.cpp
# apps/ui_keyfob.cpp
# apps/ui_lcr.cpp
apps/ui_level.cpp
apps/ui_level.cpp
apps/ui_looking_glass_app.cpp
apps/ui_mictx.cpp
apps/ui_modemsetup.cpp
@@ -304,7 +304,7 @@ set(CPPSRC
apps/ui_pocsag_tx.cpp
apps/ui_rds.cpp
apps/ui_recon_settings.cpp
apps/ui_recon.cpp
apps/ui_recon.cpp
apps/ui_remote.cpp
apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp
@@ -347,10 +347,12 @@ set(CPPSRC
${HACKRF_CPLD_DATA_CPP}
ui_external_items_menu_loader.cpp
view_factory_base.cpp
${EXTCPPSRC}
)
set_source_files_properties(${CPPSRC} PROPERTIES COMPILE_FLAGS -flto) # Add lto flag to the non-external sources only
list (APPEND CPPSRC ${EXTCPPSRC}) # Append external sources after setting lto flag to internal ones
# C sources to be compiled in ARM mode regardless of the global setting.
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
# option that results in lower performance and larger code size.
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+6 -6
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -51,7 +52,7 @@ void SoundBoardView::stop() {
void SoundBoardView::handle_replay_thread_done(const uint32_t return_code) {
stop();
// progressbar.set_value(0);
progressbar.set_value(0);
if (return_code == ReplayThread::END_OF_FILE) {
if (check_random.value()) {
@@ -100,7 +101,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
playing_id = id;
// progressbar.set_max(reader->sample_count());
progressbar.set_max(reader->sample_count());
// button_play.set_bitmap(&bitmap_stop);
@@ -148,8 +149,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
}*/
void SoundBoardView::on_tx_progress(const uint32_t progress) {
(void)progress; // avoid warning
// progressbar.set_value(progress);
progressbar.set_value(progress);
}
void SoundBoardView::on_select_entry() {
@@ -213,7 +213,7 @@ void SoundBoardView::refresh_list() {
for (size_t n = 0; n < file_list.size(); n++) {
menu_view.add_item({file_list[n].string().substr(0, 30),
ui::Color::white(),
ui::Color::dark_magenta(),
nullptr,
[this](KeyEvent) {
on_select_entry();
@@ -240,7 +240,7 @@ SoundBoardView::SoundBoardView(
&options_tone_key,
//&text_title,
//&text_duration,
//&progressbar,
&progressbar,
&field_volume,
&text_volume_disabled,
&page_info,
+4 -4
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -103,7 +104,7 @@ class SoundBoardView : public View {
"<="};
Text page_info{
{0, 30 * 8 - 4, 30 * 8, 16}};
{0, 29 * 8, 30 * 8, 16}};
MenuView menu_view{
{0, 0, 240, 175},
@@ -142,9 +143,8 @@ class SoundBoardView : public View {
6,
"Random"};
// ProgressBar progressbar {
// { 0 * 8, 30 * 8 - 4, 30 * 8, 16 }
// };
ProgressBar progressbar{
{0 * 8, 31 * 8 + 2, 30 * 8, 4}};
TransmitterView tx_view{
16 * 16,
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+20
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -322,6 +323,11 @@ bool ControlsSwitchesWidget::on_key(const KeyEvent key) {
return true;
}
bool ControlsSwitchesWidget::on_encoder(const EncoderEvent delta) {
last_delta = delta;
return true;
}
void ControlsSwitchesWidget::paint(Painter& painter) {
const auto pos = screen_pos();
@@ -404,6 +410,8 @@ void ControlsSwitchesWidget::paint(Painter& painter) {
switches_event >>= 1;
}
painter.draw_string({5 * 8, 12 * 16}, Styles::light_grey, to_string_dec_int(last_delta, 3));
}
void ControlsSwitchesWidget::on_frame_sync() {
@@ -449,6 +457,17 @@ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) {
set_max_rows(2); // allow wider buttons
}
/* DebugReboot **********************************************/
DebugReboot::DebugReboot(NavigationView& nav) {
(void)nav;
LPC_RGU->RESET_CTRL[0] = (1 << 0);
while (1)
__WFE();
}
/* DebugMenuView *********************************************************/
DebugMenuView::DebugMenuView(NavigationView& nav) {
@@ -464,6 +483,7 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push<DebugPeripheralsMenuView>(); }},
{"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
//{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
{"Reboot", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push<DebugReboot>(); }},
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SDCardDebugView>(); }},
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
{"Touch Test", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<DebugScreenTest>(); }},
+11 -1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -251,18 +252,21 @@ class ControlsSwitchesWidget : public Widget {
Rect parent_rect)
: Widget{parent_rect},
key_event_mask(0),
long_press_key_event_mask{0} {
long_press_key_event_mask{0},
last_delta{0} {
set_focusable(true);
}
void on_show() override;
bool on_key(const KeyEvent key) override;
bool on_encoder(const EncoderEvent delta) override;
void paint(Painter& painter) override;
private:
uint8_t key_event_mask;
uint8_t long_press_key_event_mask;
EncoderEvent last_delta;
MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync,
@@ -284,6 +288,7 @@ class DebugControlsView : public View {
private:
Labels labels{
{{8 * 8, 1 * 16}, "Controls State", Color::white()},
{{0 * 8, 11 * 16}, "Dial:", Color::grey()},
{{0 * 8, 14 * 16}, "Long-Press Mode:", Color::grey()}};
ControlsSwitchesWidget switches_widget{
@@ -419,6 +424,11 @@ class DebugPeripheralsMenuView : public BtnGridView {
std::string title() const override { return "Peripherals"; };
};
class DebugReboot : public BtnGridView {
public:
DebugReboot(NavigationView& nav);
};
class DebugMenuView : public BtnGridView {
public:
DebugMenuView(NavigationView& nav);
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Bernd Herzog
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Bernd Herzog
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+26 -4
View File
@@ -28,27 +28,49 @@ namespace ui {
static const char16_t* firmware_folder = u"/FIRMWARE";
// Firmware image validation
static const char* hackrf_magic = "HACKRFFW";
#define FIRMWARE_INFO_AREA_OFFSET 0x400
#define FIRST_CHECKSUM_NIGHTLY 240125
Thread* FlashUtilityView::thread{nullptr};
static constexpr size_t max_filename_length = 26;
bool valid_firmware_file(std::filesystem::path::string_type path) {
File firmware_file;
bool require_checksum{false};
uint32_t read_buffer[128];
uint32_t checksum{(uint32_t)~FLASH_EXPECTED_CHECKSUM}; // initializing to invalid checksum in case file can't be read
uint32_t checksum{FLASH_CHECKSUM_ERROR}; // initializing to invalid checksum in case file can't be read
static_assert((FIRMWARE_INFO_AREA_OFFSET % sizeof(read_buffer)) == 0, "Read buffer size must divide evenly into FIRMWARE_INFO_AREA_OFFSET");
// test read of the whole file just to validate checksum (baseband flash code will re-read when flashing)
auto result = firmware_file.open(path.c_str());
if (!result.is_valid()) {
checksum = 0;
for (uint32_t i = 0; i < FLASH_ROM_SIZE / sizeof(read_buffer); i++) {
for (uint32_t offset = 0; offset < FLASH_ROM_SIZE; offset += sizeof(read_buffer)) {
auto readResult = firmware_file.read(&read_buffer, sizeof(read_buffer));
// if file is smaller than 1MB, assume it's a downgrade to an old FW version and ignore the checksum
if ((!readResult) || (readResult.value() != sizeof(read_buffer))) {
checksum = FLASH_EXPECTED_CHECKSUM;
// File was smaller than 1MB:
// If version is such that the file SHOULD have been 1MB, call it a checksum error (otherwise say it's OK).
checksum = (require_checksum) ? FLASH_CHECKSUM_ERROR : FLASH_EXPECTED_CHECKSUM;
break;
}
// Did we just read the firmware info area?
if (offset == FIRMWARE_INFO_AREA_OFFSET) {
// If there's no info area (missing HACKRFFW signature), it could be an ancient FW version (so skipping check)
if (memcmp(read_buffer, hackrf_magic, 8) == 0) {
char* version_string = (char*)&read_buffer[4];
// Require a 1MB firmware image with a valid checksum if release version >=v2.x or nightly >n_240125
if (((version_string[0] == 'v') && (std::atoi(&version_string[1]) >= 2)) ||
((version_string[0] == 'n') && (version_string[1] == '_') && (std::atoi(&version_string[2]) >= FIRST_CHECKSUM_NIGHTLY)))
require_checksum = true;
}
}
checksum += simple_checksum((uint32_t)read_buffer, sizeof(read_buffer));
}
}
@@ -35,6 +35,7 @@
#define FLASH_ROM_SIZE 1048576
#define FLASH_STARTING_ADDRESS 0x00000000
#define FLASH_EXPECTED_CHECKSUM 0x00000000
#define FLASH_CHECKSUM_ERROR 0xFFFFFFFF
namespace ui {
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+2 -1
View File
@@ -3,6 +3,7 @@
* Copyright (C) 2016 Furrtek
* Copyleft () 2022 NotPike
* Copyright (C) 2023 Kyle Reed, zxkmm
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -389,7 +390,7 @@ PlaylistView::PlaylistView(
ensure_directory(u"PLAYLIST");
waterfall.show_audio_spectrum_view(false);
field_frequency.set_value(100'000'000);
field_frequency.set_value(transmitter_model.target_frequency());
field_frequency.on_change = [this](rf::Frequency f) {
if (current())
current()->metadata.center_frequency = f;
+2 -1
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Kyle Reed, zxkmm
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -56,7 +57,7 @@ class PlaylistView : public View {
NavigationView& nav_;
TxRadioState radio_state_{};
app_settings::SettingsManager settings_{
"tx_playlist", app_settings::Mode::TX};
"tx_replay", app_settings::Mode::TX};
// More header == less spectrum view.
static constexpr ui::Dim header_height = 6 * 16;
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+89 -1
View File
@@ -3,6 +3,8 @@
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
*
@@ -42,6 +44,7 @@ namespace fs = std::filesystem;
#include "string_format.hpp"
#include "ui_styles.hpp"
#include "ui_font_fixed_8x16.hpp"
#include "cpld_update.hpp"
#include "config_mode.hpp"
@@ -314,6 +317,7 @@ SetUIView::SetUIView(NavigationView& nav) {
&toggle_bias_tee,
&toggle_clock,
&toggle_mute,
&toggle_fake_brightness,
&toggle_sd_card,
&button_save,
&button_cancel});
@@ -347,6 +351,7 @@ SetUIView::SetUIView(NavigationView& nav) {
toggle_clock.set_value(!pmem::ui_hide_clock());
toggle_speaker.set_value(!pmem::ui_hide_speaker());
toggle_mute.set_value(!pmem::ui_hide_mute());
toggle_fake_brightness.set_value(!pmem::ui_hide_fake_brightness());
toggle_sd_card.set_value(!pmem::ui_hide_sd_card());
button_save.on_select = [&nav, this](Button&) {
@@ -373,6 +378,7 @@ SetUIView::SetUIView(NavigationView& nav) {
pmem::set_ui_hide_clock(!toggle_clock.value());
pmem::set_ui_hide_speaker(!toggle_speaker.value());
pmem::set_ui_hide_mute(!toggle_mute.value());
pmem::set_ui_hide_fake_brightness(!toggle_fake_brightness.value());
pmem::set_ui_hide_sd_card(!toggle_sd_card.value());
send_system_refresh();
@@ -607,6 +613,8 @@ SetPersistentMemoryView::SetPersistentMemoryView(NavigationView& nav) {
[this](bool choice) {
if (choice) {
pmem::cache::defaults();
// Refresh status bar
send_system_refresh();
}
});
};
@@ -676,13 +684,16 @@ void SetQRCodeView::focus() {
SetEncoderDialView::SetEncoderDialView(NavigationView& nav) {
add_children({&labels,
&field_encoder_dial_sensitivity,
&field_encoder_rate_multiplier,
&button_save,
&button_cancel});
field_encoder_dial_sensitivity.set_by_value(pmem::config_encoder_dial_sensitivity());
field_encoder_dial_sensitivity.set_by_value(pmem::encoder_dial_sensitivity());
field_encoder_rate_multiplier.set_value(pmem::encoder_rate_multiplier());
button_save.on_select = [&nav, this](Button&) {
pmem::set_encoder_dial_sensitivity(field_encoder_dial_sensitivity.selected_index_value());
pmem::set_encoder_rate_multiplier(field_encoder_rate_multiplier.value());
nav.pop();
};
@@ -747,6 +758,81 @@ void SetConfigModeView::focus() {
button_save.focus();
}
/* SetFakeBrightnessView ************************************/
SetFakeBrightnessView::SetFakeBrightnessView(NavigationView& nav) {
add_children({&labels,
&field_fake_brightness,
&button_save,
&button_cancel,
&checkbox_brightness_switch});
field_fake_brightness.set_by_value(pmem::fake_brightness_level());
checkbox_brightness_switch.set_value(pmem::apply_fake_brightness());
button_save.on_select = [&nav, this](Button&) {
pmem::set_apply_fake_brightness(checkbox_brightness_switch.value());
pmem::set_fake_brightness_level(field_fake_brightness.selected_index_value());
send_system_refresh();
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetFakeBrightnessView::focus() {
button_save.focus();
}
/* SetMenuColorView ************************************/
void SetMenuColorView::paint_sample() {
Color c = Color(field_red_level.value(), field_green_level.value(), field_blue_level.value());
button_sample.set_bg_color(c);
}
SetMenuColorView::SetMenuColorView(NavigationView& nav) {
add_children({&labels,
&button_sample,
&field_red_level,
&field_green_level,
&field_blue_level,
&button_save,
&button_cancel});
button_sample.set_focusable(false);
Color c = pmem::menu_color();
field_red_level.set_value(c.r());
field_green_level.set_value(c.g());
field_blue_level.set_value(c.b());
paint_sample();
const auto color_changed_fn = [this](int32_t) {
paint_sample();
};
field_red_level.on_change = color_changed_fn;
field_green_level.on_change = color_changed_fn;
field_blue_level.on_change = color_changed_fn;
button_save.on_select = [&nav, this](Button&) {
Color c = Color(field_red_level.value(), field_green_level.value(), field_blue_level.value());
pmem::set_menu_color(c);
send_system_refresh();
nav.pop();
};
button_cancel.on_select = [&nav, this](Button&) {
nav.pop();
};
}
void SetMenuColorView::focus() {
button_save.focus();
}
/* SettingsMenuView **************************************/
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
@@ -767,6 +853,8 @@ SettingsMenuView::SettingsMenuView(NavigationView& nav) {
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SetSDCardView>(); }},
{"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [&nav]() { nav.push<SetUIView>(); }},
{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push<SetQRCodeView>(); }},
{"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push<SetFakeBrightnessView>(); }},
{"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [&nav]() { nav.push<SetMenuColorView>(); }},
});
set_max_rows(2); // allow wider buttons
}
+130 -13
View File
@@ -3,6 +3,8 @@
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
*
@@ -320,39 +322,43 @@ class SetUIView : public View {
};
ImageToggle toggle_camera{
{7 * 8, 14 * 16 + 2, 16, 16},
{6 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_camera};
ImageToggle toggle_sleep{
{9 * 8, 14 * 16 + 2, 16, 16},
{8 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_sleep};
ImageToggle toggle_stealth{
{11 * 8, 14 * 16 + 2, 16, 16},
{10 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_stealth};
ImageToggle toggle_converter{
{13 * 8, 14 * 16 + 2, 16, 16},
{12 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_upconvert};
ImageToggle toggle_bias_tee{
{15 * 8, 14 * 16 + 2, 16, 16},
{14 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_biast_off};
ImageToggle toggle_clock{
{17 * 8, 14 * 16 + 2, 8, 16},
{16 * 8, 14 * 16 + 2, 8, 16},
&bitmap_icon_clk_ext};
ImageToggle toggle_mute{
{18 * 8, 14 * 16 + 2, 16, 16},
{17 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_speaker_and_headphones_mute};
ImageToggle toggle_speaker{
{20 * 8, 14 * 16 + 2, 16, 16},
{19 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_speaker_mute};
ImageToggle toggle_fake_brightness{
{21 * 8, 14 * 16 + 2, 16, 16},
&bitmap_icon_brightness};
ImageToggle toggle_sd_card{
{22 * 8, 14 * 16 + 2, 16, 16},
{23 * 8, 14 * 16 + 2, 16, 16},
&bitmap_sd_card_ok};
Button button_save{
@@ -550,6 +556,7 @@ class SetQRCodeView : public View {
};
using portapack::persistent_memory::encoder_dial_sensitivity;
using portapack::persistent_memory::encoder_rate_multiplier;
class SetEncoderDialView : public View {
public:
@@ -561,18 +568,30 @@ class SetEncoderDialView : public View {
private:
Labels labels{
{{1 * 8, 1 * 16}, "Adjusts how many steps to", Color::light_grey()},
{{1 * 8, 2 * 16}, "change the encoder value.", Color::light_grey()},
{{2 * 8, 4 * 16}, "Dial sensitivity:", Color::light_grey()},
{{1 * 8, 1 * 16}, "Adjusts sensitivity to dial", Color::light_grey()},
{{1 * 8, 2 * 16}, "rotation position (number of", Color::light_grey()},
{{1 * 8, 3 * 16}, "steps per full rotation):", Color::light_grey()},
{{2 * 8, 5 * 16}, "Dial sensitivity:", Color::light_grey()},
{{1 * 8, 8 * 16}, "Adjusts sensitivity to dial", Color::light_grey()},
{{1 * 8, 9 * 16}, "rotation rate (default 1", Color::light_grey()},
{{1 * 8, 10 * 16}, "means no rate dependency):", Color::light_grey()},
{{3 * 8, 12 * 16}, "Rate multiplier:", Color::light_grey()},
};
OptionsField field_encoder_dial_sensitivity{
{20 * 8, 4 * 16},
{20 * 8, 5 * 16},
6,
{{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW},
{"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL},
{"HIGH", encoder_dial_sensitivity::DIAL_SENSITIVITY_HIGH}}};
NumberField field_encoder_rate_multiplier{
{20 * 8, 12 * 16},
2,
{1, 15},
1,
' '};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
@@ -672,6 +691,104 @@ class SetConfigModeView : public View {
};
};
using portapack::persistent_memory::fake_brightness_level_options;
class SetFakeBrightnessView : public View {
public:
SetFakeBrightnessView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Brightness"; };
private:
Labels labels{
{{1 * 8, 1 * 16}, "Limits screen brightness", Color::light_grey()},
{{1 * 8, 2 * 16}, "(has a small performance", Color::light_grey()},
{{1 * 8, 3 * 16}, "impact when enabled).", Color::light_grey()},
{{2 * 8, 8 * 16}, "Brightness:", Color::light_grey()},
};
OptionsField field_fake_brightness{
{20 * 8, 8 * 16},
6,
{{"12.5%", fake_brightness_level_options::BRIGHTNESS_12p5},
{"25%", fake_brightness_level_options::BRIGHTNESS_25},
{"50%", fake_brightness_level_options::BRIGHTNESS_50}}};
Checkbox checkbox_brightness_switch{
{1 * 8, 5 * 16},
16,
"Enable brightness adjust"};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
Button button_cancel{
{16 * 8, 16 * 16, 12 * 8, 32},
"Cancel",
};
};
class SetMenuColorView : public View {
public:
SetMenuColorView(NavigationView& nav);
void focus() override;
std::string title() const override { return "Menu Color"; };
private:
void paint_sample();
Labels labels{
{{3 * 8, 1 * 16}, "Menu Button Color Scheme", Color::light_grey()},
{{2 * 8, 8 * 16}, "Red Level:", Color::light_grey()},
{{2 * 8, 9 * 16}, "Green Level:", Color::light_grey()},
{{2 * 8, 10 * 16}, "Blue Level:", Color::light_grey()},
};
NewButton button_sample{
{8 * 8, 4 * 16, 14 * 8, 3 * 16},
"New Color",
&bitmap_icon_brightness,
};
NumberField field_red_level{
{15 * 8, 8 * 16},
3,
{8, 248},
8,
' ',
};
NumberField field_green_level{
{15 * 8, 9 * 16},
3,
{8, 248},
8,
' ',
};
NumberField field_blue_level{
{15 * 8, 10 * 16},
3,
{8, 248},
8,
' ',
};
Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32},
"Save"};
Button button_cancel{
{16 * 8, 16 * 16, 12 * 8, 32},
"Cancel",
};
};
class SettingsMenuView : public BtnGridView {
public:
SettingsMenuView(NavigationView& nav);
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -424,6 +425,9 @@ TextEditorView::TextEditorView(NavigationView& nav)
&text_size,
});
text_position.set_style(&Styles::bg_dark_blue);
text_size.set_style(&Styles::bg_dark_blue);
viewer.set_font_zoom(enable_zoom);
viewer.on_select = [this]() {
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2023 Kyle Reed
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+22 -4
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -38,6 +39,13 @@ void ViewWavView::update_scale(int32_t new_scale) {
}
void ViewWavView::refresh_waveform() {
// NB: We can't read from the file to update the waveform when playback is in progress, so defer til playback done.
// (This only happens if the user messes with position or scale fields while playback is occurring)
if (playback_in_progress) {
waveform_update_needed = true;
return;
}
uint8_t bits_per_sample = wav_reader->bits_per_sample();
for (size_t i = 0; i < 240; i++) {
@@ -151,6 +159,10 @@ void ViewWavView::reset_controls() {
field_pos_samples.set_value(0);
field_cursor_a.set_value(0);
field_cursor_b.set_value(0);
field_pos_seconds.set_range(0, wav_reader->ms_duration() / 1000);
field_pos_milliseconds.set_range(0, (wav_reader->ms_duration() < 1000) ? wav_reader->ms_duration() % 1000 : 999);
field_pos_samples.set_range(0, wav_reader->sample_count() - 1);
field_scale.set_range(1, std::min(99999ul, wav_reader->sample_count() / 240));
}
bool ViewWavView::is_active() {
@@ -175,6 +187,13 @@ void ViewWavView::handle_replay_thread_done(const uint32_t return_code) {
if (return_code == ReplayThread::READ_ERROR)
file_error();
// Playback complete - now it's safe to update waveform view
playback_in_progress = false;
if (waveform_update_needed) {
waveform_update_needed = false;
refresh_waveform();
}
}
void ViewWavView::set_ready() {
@@ -198,6 +217,8 @@ void ViewWavView::start_playback() {
return;
}
playback_in_progress = true;
button_play.set_bitmap(&bitmap_stop);
sample_rate = reader->sample_rate();
@@ -234,6 +255,7 @@ void ViewWavView::start_playback() {
void ViewWavView::on_playback_progress(const uint32_t progress) {
progressbar.set_value(progress);
field_pos_samples.set_value(progress);
}
ViewWavView::ViewWavView(
@@ -278,10 +300,6 @@ ViewWavView::ViewWavView(
}
load_wav(file_path);
field_pos_seconds.focus();
field_pos_seconds.set_range(0, wav_reader->ms_duration() / 1000);
field_pos_milliseconds.set_range(0, (wav_reader->ms_duration() < 1000) ? wav_reader->ms_duration() % 1000 : 999);
field_pos_samples.set_range(0, wav_reader->sample_count() - 1);
field_scale.set_range(1, wav_reader->sample_count() / 240);
});
};
};
+8 -5
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -76,13 +77,15 @@ class ViewWavView : public View {
uint64_t ns_per_pixel{};
uint64_t position{};
bool updating_position{false};
bool playback_in_progress{false};
bool waveform_update_needed{false};
Labels labels{
{{0 * 8, 0 * 16}, "File:", Color::light_grey()},
{{2 * 8, 1 * 16}, "-bit mono", Color::light_grey()},
{{0 * 8, 2 * 16}, "Title:", Color::light_grey()},
{{0 * 8, 3 * 16}, "Duration:", Color::light_grey()},
{{0 * 8, 12 * 16}, "Position: . s Scale:", Color::light_grey()},
{{0 * 8, 12 * 16}, "Position: . s Scale:", Color::light_grey()},
{{0 * 8, 13 * 16}, " Sample:", Color::light_grey()},
{{0 * 8, 14 * 16}, "Cursor A:", Color::dark_cyan()},
{{0 * 8, 15 * 16}, "Cursor B:", Color::dark_magenta()},
@@ -124,7 +127,7 @@ class ViewWavView : public View {
Color::white()};
ProgressBar progressbar{
{0 * 8, 11 * 16, 30 * 8, 8}};
{0 * 8, 11 * 16, 30 * 8, 4}};
NumberField field_pos_seconds{
{9 * 8, 12 * 16},
@@ -148,9 +151,9 @@ class ViewWavView : public View {
'0',
true};
NumberField field_scale{
{26 * 8, 12 * 16},
4,
{1, 9999},
{25 * 8, 12 * 16},
5,
{1, 1},
1,
' ',
true};
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+38
View File
@@ -5759,6 +5759,44 @@ static constexpr Bitmap bitmap_icon_thermometer{
{16, 16},
bitmap_icon_thermometer_data};
static constexpr uint8_t bitmap_icon_brightness_data[] = {
0x00,
0x00,
0x80,
0x01,
0x84,
0x21,
0x08,
0x10,
0xC0,
0x03,
0xE0,
0x07,
0xF0,
0x0F,
0xF6,
0x6F,
0xF6,
0x6F,
0xF0,
0x0F,
0xE0,
0x07,
0xC0,
0x03,
0x08,
0x10,
0x84,
0x21,
0x80,
0x01,
0x00,
0x00,
};
static constexpr Bitmap bitmap_icon_brightness{
{16, 16},
bitmap_icon_brightness_data};
} /* namespace ui */
#endif /*__BITMAP_HPP__*/
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Bernd Herzog
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Bernd Herzog
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+6
View File
@@ -44,6 +44,8 @@ using namespace lpc43xx;
#include "ui_navigation.hpp"
static int delayed_error = 0;
extern "C" {
CH_IRQ_HANDLER(M4Core_IRQHandler) {
@@ -161,6 +163,10 @@ void EventDispatcher::dispatch(const eventmask_t events) {
}
if (events & EVT_MASK_RTC_TICK) {
// delay error message by 2 seconds to wait for LCD being ready
if (portapack::init_error != nullptr && ++delayed_error > 1)
draw_guru_meditation(CORTEX_M4, portapack::init_error);
handle_rtc_tick();
}
+1 -1
View File
@@ -1867,7 +1867,7 @@ static byte menuselect(byte lines) { // Selection (1 line = 16 items)
// *** S T A C K
static void floatstack() {
memcpy(ds, &ds[1], (DATASTACKSIZE - 1) * sizeof(double));
memmove(ds, &ds[1], (DATASTACKSIZE - 1) * sizeof(double));
dp--;
}
+6
View File
@@ -62,6 +62,11 @@ set(EXTCPPSRC
external/keyfob/main.cpp
external/keyfob/ui_keyfob.cpp
external/keyfob/ui_keyfob.hpp
#extsensors
external/extsensors/main.cpp
external/extsensors/ui_extsensors.cpp
external/extsensors/ui_extsensors.hpp
)
set(EXTAPPLIST
@@ -80,4 +85,5 @@ set(EXTAPPLIST
spainter
keyfob
tetris
extsensors
)
+31 -20
View File
@@ -1,5 +1,6 @@
/*
Copyright (C) 2023 Bernd Herzog
Copyright (C) 2024 Mark Thompson
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,22 +17,28 @@
MEMORY
{
/* external apps: regions can't overlap so addresses are corrected after build */
ram_external_app_pacman (rwx) : org = 0xEEE90000, len = 32k
ram_external_app_afsk_rx (rwx) : org = 0xEEEA0000, len = 32k
ram_external_app_calculator (rwx) : org = 0xEEEB0000, len = 32k
ram_external_app_font_viewer(rwx) : org = 0xEEEC0000, len = 32k
ram_external_app_blespam(rwx) : org = 0xEEED0000, len = 32k
ram_external_app_analogtv(rwx) : org = 0xEEEE0000, len = 32k
ram_external_app_nrf_rx(rwx) : org = 0xEEEF0000, len = 32k
ram_external_app_coasterp(rwx) : org = 0xEEF00000, len = 32k
ram_external_app_lge(rwx) : org = 0xEEF10000, len = 32k
ram_external_app_lcr(rwx) : org = 0xEEF20000, len = 32k
ram_external_app_jammer(rwx) : org = 0xEEF30000, len = 32k
ram_external_app_gpssim(rwx) : org = 0xEEF40000, len = 32k
ram_external_app_spainter(rwx) : org = 0xEEF50000, len = 32k
ram_external_app_keyfob(rwx) : org = 0xEEF60000, len = 32k
ram_external_app_tetris(rwx) : org = 0xEEF70000, len = 32k
/*
* External apps: regions can't overlap so addresses are corrected after build.
* Picking uncommon address values for search & replace in binaries (no false positives) - 0xADB00000-0xADEF0000 seems to be good.
* Also need to consider processor memory map - reading 0xADxxxxxx generates a fault which may be better than unexpected behavior.
* External app address ranges below must match those in python file "external_app_info.py".
*/
ram_external_app_pacman (rwx) : org = 0xADB00000, len = 32k
ram_external_app_afsk_rx (rwx) : org = 0xADB10000, len = 32k
ram_external_app_calculator (rwx) : org = 0xADB20000, len = 32k
ram_external_app_font_viewer(rwx) : org = 0xADB30000, len = 32k
ram_external_app_blespam(rwx) : org = 0xADB40000, len = 32k
ram_external_app_analogtv(rwx) : org = 0xADB50000, len = 32k
ram_external_app_nrf_rx(rwx) : org = 0xADB60000, len = 32k
ram_external_app_coasterp(rwx) : org = 0xADB70000, len = 32k
ram_external_app_lge(rwx) : org = 0xADB80000, len = 32k
ram_external_app_lcr(rwx) : org = 0xADB90000, len = 32k
ram_external_app_jammer(rwx) : org = 0xADBA0000, len = 32k
ram_external_app_gpssim(rwx) : org = 0xADBB0000, len = 32k
ram_external_app_spainter(rwx) : org = 0xADBC0000, len = 32k
ram_external_app_keyfob(rwx) : org = 0xADBD0000, len = 32k
ram_external_app_tetris(rwx) : org = 0xADBE0000, len = 32k
ram_external_app_extsensors(rwx) : org = 0xADBF0000, len = 32k
}
SECTIONS
@@ -60,7 +67,6 @@ SECTIONS
*(*ui*external_app*font_viewer*);
} > ram_external_app_font_viewer
.external_app_blespam : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_blespam.application_information));
@@ -91,14 +97,12 @@ SECTIONS
*(*ui*external_app*lge*);
} > ram_external_app_lge
.external_app_lcr : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_lcr.application_information));
*(*ui*external_app*lcr*);
} > ram_external_app_lcr
.external_app_jammer : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_jammer.application_information));
@@ -111,7 +115,6 @@ SECTIONS
*(*ui*external_app*gpssim*);
} > ram_external_app_gpssim
.external_app_spainter : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_spainter.application_information));
@@ -130,4 +133,12 @@ SECTIONS
*(*ui*external_app*tetris*);
} > ram_external_app_tetris
.external_app_extsensors : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_extsensors.application_information));
*(*ui*external_app*extsensors*);
} > ram_external_app_extsensors
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_extsensors.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::extsensors {
void initialize_app(ui::NavigationView& nav) {
nav.push<ExtSensorsView>();
}
} // namespace ui::external_app::extsensors
extern "C" {
__attribute__((section(".external_app.app_extsensors.application_information"), used)) application_information_t _application_information_extsensors = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::extsensors::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "ExtSensor",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
0x00,
0x04,
0x20,
0x12,
0x48,
0x8A,
0x51,
0xCA,
0x53,
0xCA,
0x53,
0x8A,
0x51,
0x12,
0x48,
0x84,
0x21,
0xC0,
0x03,
0x40,
0x02,
0x60,
0x06,
0x20,
0x04,
0x30,
0x0C,
0xF0,
0x0F,
},
/*.icon_color = */ ui::Color::orange().v,
/*.menu_location = */ app_location_t::DEBUG,
/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {0, 0, 0, 0},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -0,0 +1,86 @@
/*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_extsensors.hpp"
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
using namespace ui;
namespace ui::external_app::extsensors {
void ExtSensorsView::focus() {
text_info.focus();
}
ExtSensorsView::ExtSensorsView(NavigationView& nav)
: nav_{nav} {
add_children({&labels,
&text_info,
&text_gps,
&text_orientation,
&text_envl1,
&text_envl2});
}
ExtSensorsView::~ExtSensorsView() {
}
void ExtSensorsView::on_any() {
if (has_data == false) {
// update text
text_info.set("Found ext module."); // todo do an ext module check for type
}
has_data = true;
}
void ExtSensorsView::on_gps(const GPSPosDataMessage* msg) {
on_any();
std::string tmp = to_string_decimal(msg->lat, 5);
tmp += "; ";
tmp += to_string_decimal(msg->lon, 5);
text_gps.set(tmp);
}
void ExtSensorsView::on_orientation(const OrientationDataMessage* msg) {
on_any();
std::string tmp = to_string_dec_uint(msg->angle);
tmp += (char)176; // °
if (msg->tilt < 400) {
tmp += "; T: " + to_string_dec_int(msg->tilt);
}
text_orientation.set(tmp);
}
void ExtSensorsView::on_environment(const EnvironmentDataMessage* msg) {
on_any();
std::string tmp = "T: " + to_string_decimal(msg->temperature, 2); // temperature
tmp += (char)176; // °
tmp += "C";
tmp += "; H: " + to_string_decimal(msg->humidity, 1) + "%"; // humidity
text_envl1.set(tmp);
tmp = "P: " + to_string_decimal(msg->pressure, 1) + " hPa; L:"; // pressure
tmp += to_string_dec_int(msg->light) + " LUX"; // light
text_envl2.set(tmp);
}
} // namespace ui::external_app::extsensors
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
// Code from https://github.com/Flipper-XFW/Xtreme-Apps/tree/04c3a60093e2c2378e79498b4505aa8072980a42/ble_spam/protocols
// Thanks for the work of the original creators!
// Saying thanks in the main view!
#ifndef __UI_EXTSENSORS_H__
#define __UI_EXTSENSORS_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_record_view.hpp"
#include "app_settings.hpp"
#include "utility.hpp"
using namespace ui;
namespace ui::external_app::extsensors {
class ExtSensorsView : public View {
public:
ExtSensorsView(NavigationView& nav);
~ExtSensorsView();
void focus() override;
std::string title() const override {
return "ExtSensor";
};
private:
NavigationView& nav_;
bool has_data = false;
Labels labels{
{{0 * 8, 3 * 16}, "GPS:", Color::light_grey()},
{{0 * 8, 5 * 16}, "ORI:", Color::light_grey()},
{{0 * 8, 7 * 16}, "ENV:", Color::light_grey()}};
Text text_info{{0 * 8, 0 * 8, 30 * 8, 16 * 1}, "Connect a compatible module..."};
Text text_gps{{5 * 8, 3 * 16, 24 * 8, 16}, "-"};
Text text_orientation{{5 * 8, 5 * 16, 24 * 8, 16}, "-"};
Text text_envl1{{5 * 8, 7 * 16, 24 * 8, 16}, "-"};
Text text_envl2{{1 * 8, 9 * 16, 24 * 8, 16}, "-"};
void on_any();
void on_gps(const GPSPosDataMessage* msg);
void on_orientation(const OrientationDataMessage* msg);
void on_environment(const EnvironmentDataMessage* msg);
MessageHandlerRegistration message_handler_gps{
Message::ID::GPSPosData,
[this](Message* const p) {
const auto message = static_cast<const GPSPosDataMessage*>(p);
this->on_gps(message);
}};
MessageHandlerRegistration message_handler_orientation{
Message::ID::OrientationData,
[this](Message* const p) {
const auto message = static_cast<const OrientationDataMessage*>(p);
this->on_orientation(message);
}};
MessageHandlerRegistration message_handler_environment{
Message::ID::EnvironmentData,
[this](Message* const p) {
const auto message = static_cast<const EnvironmentDataMessage*>(p);
this->on_environment(message);
}};
};
}; // namespace ui::external_app::extsensors
#endif /*__UI_EXTSENSORS_H__*/
+62 -17
View File
@@ -43,6 +43,16 @@ boolean but_DOWN = false; // 50
boolean but_LEFT = false; // 48
boolean but_RIGHT = false; // 46
enum cheat_code_keymap {
UP,
DOWN,
LEFT,
RIGHT
};
enum cheat_code_keymap cheat_code[] = {UP, DOWN, UP, DOWN, RIGHT, LEFT, RIGHT, LEFT};
byte cheat_code_index = 0;
/******************************************************************************/
/* GAME VARIABLES AND DEFINITIONS */
/******************************************************************************/
@@ -1280,29 +1290,64 @@ class Playfield {
but_A = false;
GAMEPAUSED = 1;
} else if (but_LEFT && DEMO == 1 && GAMEPAUSED == 0) { // -level
cheat_level = true;
if ((cheat_code[cheat_code_index] == 2) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_level = true;
if (LEVEL > 1) {
LEVEL--;
}
Init();
}
but_LEFT = false;
if (LEVEL > 1) {
LEVEL--;
}
Init();
} else if (but_RIGHT && DEMO == 1 && GAMEPAUSED == 0) { // +level
cheat_level = true;
but_RIGHT = false;
if (LEVEL < 255) {
LEVEL++;
if ((cheat_code[cheat_code_index] == 3) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
Init();
if (cheat_code_index == 8) {
cheat_level = true;
if (LEVEL < 255) {
LEVEL++;
}
Init();
}
but_RIGHT = false;
} else if (but_UP && DEMO == 1 && GAMEPAUSED == 0) { // full of lifes
cheat_lifes = true;
if ((cheat_code[cheat_code_index] == 0) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_lifes = true;
Init();
}
but_UP = false;
Init();
} else if (but_DOWN && DEMO == 1 && GAMEPAUSED == 0) { // reset
cheat_level = false;
cheat_lifes = false;
but_DOWN = false;
LIFES = START_LIFES;
Init();
if ((cheat_code[cheat_code_index] == 1) && (cheat_code_index <= 8)) {
cheat_code_index++;
}
if (cheat_code_index == 8) {
cheat_level = false;
cheat_lifes = false;
but_DOWN = false;
LIFES = START_LIFES;
cheat_code_index = 0;
Init();
}
}
if (GAMEPAUSED && but_A && DEMO == 0) {
+22 -7
View File
@@ -13,8 +13,6 @@ namespace ui::external_app::pacman {
#include "playfield.hpp"
#pragma GCC diagnostic pop
Playfield _game;
PacmanView::PacmanView(NavigationView& nav)
: nav_(nav) {
add_children({&dummy});
@@ -26,19 +24,36 @@ void PacmanView::focus() {
void PacmanView::paint(Painter& painter) {
(void)painter;
static Playfield _game;
static bool wait_for_button_release{false};
if (!initialized) {
initialized = true;
_game.Init();
}
auto switches_raw = swizzled_switches() & ((1 << (int)Switch::Right) | (1 << (int)Switch::Left) | (1 << (int)Switch::Down) | (1 << (int)Switch::Up) | (1 << (int)Switch::Sel) | (1 << (int)Switch::Dfu));
auto switches_debounced = get_switches_state().to_ulong();
but_RIGHT = (switches_debounced & 0x01) == 0x01;
but_LEFT = (switches_debounced & 0x02) == 0x02;
but_DOWN = (switches_debounced & 0x04) == 0x04;
but_UP = (switches_debounced & 0x08) == 0x08;
but_A = (switches_debounced & 0x10) == 0x10;
// For the Select (Start/Pause) button, wait for release to avoid repeat
uint8_t buttons_to_wait_for = (1 << (int)Switch::Sel);
if (wait_for_button_release) {
if ((switches_debounced & buttons_to_wait_for) == 0)
wait_for_button_release = false;
switches_debounced &= ~buttons_to_wait_for;
} else {
if (switches_debounced & buttons_to_wait_for)
wait_for_button_release = true;
}
// For the directional buttons, use the raw inputs for fastest response time
but_RIGHT = (switches_raw & (1 << (int)Switch::Right)) != 0;
but_LEFT = (switches_raw & (1 << (int)Switch::Left)) != 0;
but_DOWN = (switches_raw & (1 << (int)Switch::Down)) != 0;
but_UP = (switches_raw & (1 << (int)Switch::Up)) != 0;
// For the pause button, use the debounced input to avoid glitches, and OR in the value to make sure that we don't clear it before it's seen
but_A |= (switches_debounced & (1 << (int)Switch::Sel)) != 0;
_game.Step();
}
+30 -22
View File
@@ -56,35 +56,43 @@ static const Color pp_colors[] = {
Color::black(),
};
class SPI_TFT_ILI9341 {
public:
SPI_TFT_ILI9341(int, int, int, int, int, int, std::string) { (void)0; };
// NB: ELIMINATED SPI_TFT_ILI9341 DISPLAY CLASS DUE TO GLOBAL OBJECT INITIALIZATION ISSUE WITH EXTERNAL APPS
void claim(__FILE* x) { (void)x; };
static void claim(__FILE* x) {
(void)x;
};
void cls() {
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
};
static void cls() {
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
};
void background(int color) { bg_color = color; };
void foreground(int color) { fg_color = color; };
static void background(int color) {
bg_color = color;
};
void locate(int x, int y) {
x_pos = x;
y_pos = y;
};
void set_orientation(int x) { (void)x; };
void set_font(unsigned char* x) { (void)x; };
static void foreground(int color) {
fg_color = color;
};
void fillrect(int x1, int y1, int x2, int y2, int color) {
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
};
static void locate(int x, int y) {
x_pos = x;
y_pos = y;
};
void rect(int x1, int y1, int x2, int y2, int color) {
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
};
static void set_orientation(int x) {
(void)x;
};
private:
static void set_font(unsigned char* x) {
(void)x;
};
static void fillrect(int x1, int y1, int x2, int y2, int color) {
painter.fill_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
};
static void rect(int x1, int y1, int x2, int y2, int color) {
painter.draw_rectangle({x1, y1, x2 - x1, y2 - y1}, pp_colors[color]);
};
static void printf(std::string str) {
+1 -1
View File
@@ -67,7 +67,7 @@ static bool but_DOWN;
static bool but_SELECT;
//
// AnalogIn Class -- DID NOT WORK BECAUSE INITIALIZER CODE WON'T EXECUTE -- hacked original code module instead
// AnalogIn Class -- DID NOT WORK DUE TO GLOBAL OBJECT INITIALIZER ISSUE WITH EXTERNAL APPS -- hacked original code module instead
//
// dp9 = joystick rotate button --> select button
// dp10 = joystick y --> up & down buttons
+79 -109
View File
@@ -4,9 +4,15 @@
// clang-format off
//////// PORTAPACK CHANGES HIGHLIGHTED
//////// HACKED FOR PORTAPACK -- CHANGES HIGHLIGHTED
int main();
void pause_game();
void Initialize(unsigned char c);
void DeleteFigure();
void DrawFigure();
bool InCollisionDown(char delta);
bool InCollisionLeft();
bool InCollisionRight();
//////// PORTAPACK
#include "mbed.h"
@@ -15,32 +21,29 @@ void pause_game();
#define dp23 P0_0
//////// PORTAPACK - DISABLED MOST CLASSES DUE TO GLOBAL OBJECT INITIALIZER ISSUE WITH EXTERNAL APPS:
//deklaracija display-a
SPI_TFT_ILI9341 display(dp2, dp1, dp6, dp24, dp23, dp25, "TFT");
//////// PORTAPACK - DISABLED ANALOGIN CLASS DUE TO OBJECT INITIALIZER CODE NOT RUNNING:
//SPI_TFT_ILI9341 display(dp2, dp1, dp6, dp24, dp23, dp25, "TFT");
//
//analogni ulazi za joystick
// AnalogIn VRx(dp11);
// AnalogIn VRy(dp10);
//
// AnalogIn random(dp13); //analogni ulaz za generisanje random vrijednosti
//////// PORTAPACK
//taster na joysticku za rotaciju
InterruptIn taster(dp9);
//////// PORTAPACK - DISABLED ANALOGIN CLASS DUE TO OBJECT INITIALIZER CODE NOT RUNNING:
// AnalogIn random(dp13); //analogni ulaz za generisanje random vrijednosti
//////// PORTAPACK
//ticker za spustanje figure
//timer za debouncing tastera na joysticku
Ticker game, joystick;
Timer debounceTaster;
unsigned char level = 0; //mora biti tipa usigned char jer inače se može desiti da level bude manji od 0, a i da ne trošimo memoriju
const float delays[4] = {1.2, 0.7, 0.4, 0.25}; //svakih koliko se spusti jedan red, ovo provjeriti da li je presporo ili prebrzo, ovisi o levelu
//////// PORTAPACK - UNNEEDED JOYSTICK HYSTERESIS VARIABLES
//////// PORTAPACK - DELETED UNNEEDED JOYSTICK HYSTERESIS VARIABLES
//char leftBoundary = 1, rightBoundary = 5, downBoundary = 1, upBoundary = 5;// sada je ovo tipa char
//////// PORTAPACK
@@ -49,7 +52,6 @@ bool firstTime = true; //ako je prvi put, figura se crta u Tickeru
bool gameStarted = false;
unsigned char nextFigure = 1; //ovo je sad globalna varijabla, da bi mogli unaprijed generisati sljedeću figuru radi prikaza
//white - no figure
//I - BLUE
//O - YELLOW
@@ -69,81 +71,70 @@ short figuresY[7][4] = {{0,1,2,3}, {1,0,0,1}, {1,1,2,0}, {0,1,1,2}, {0,1,1,2}, {
unsigned int GenerateRandomSeed() {
//////// PORTAPACK - USE RTC FOR SEED
return LPC_RTC->CTIME0;
// unsigned int randomNumber = 0;
// for(int i = 0; i <= 32; i += 2) {
// randomNumber += ((random.read_u16() % 3) << i);
// wait_us(10);
// }
// return randomNumber;
//////// PORTAPACK
}
void Init() {
//ovo su zajedničke osobine za sve prikaze na display-u
//nikad se ne mijenjaju i pozvat ćemo je jednom prije petlje
display.claim(stdout);
display.set_orientation(2); // 2 ili 0, zavisi kako okrenemo display, provjerit ćemo na labu kako nam je najlakše povezat
display.set_font((unsigned char*) Arial12x12);
claim(stdout);
set_orientation(2); // 2 ili 0, zavisi kako okrenemo display, provjerit ćemo na labu kako nam je najlakše povezat
set_font((unsigned char*) Arial12x12);
}
void ShowScore() {
//pomocna funkcija za prikazivanje score-a
display.fillrect(165, 20, 235, 50, White); //popunimo pravugaonik da obrišemo stari score
display.locate(200, 35); //valjda je na sredini pravougaonika
fillrect(165, 20, 235, 50, White); //popunimo pravugaonik da obrišemo stari score
locate(200, 35); //valjda je na sredini pravougaonika
printf("%d", score);
}
void ShowNextFigure() {
//prikaz sljedeće figure koristeći pomoćnu varijablu nextFigure
display.fillrect(165, 70, 235, 120, White);
fillrect(165, 70, 235, 120, White);
int upperLeftX = 176, upperLeftY = 83;
for(int i = 0; i < 4; i++) {
int x = upperLeftX + DIMENSION_NEXT * figuresY[nextFigure - 1][i], y = upperLeftY + DIMENSION_NEXT * figuresX[nextFigure - 1][i];
display.fillrect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, colors[nextFigure]);
display.rect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, Black);
fillrect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, colors[nextFigure]);
rect(x, y, x + DIMENSION_NEXT, y + DIMENSION_NEXT, Black);
}
}
//funkcija za crtanje cursora za odabir levela
void DrawCursor(int color, unsigned char lev) {
display.fillrect(60, lev * 70 + 50, 72, lev * 70 + 50 + 12, color);
fillrect(60, lev * 70 + 50, 72, lev * 70 + 50 + 12, color);
}
// PORTAPACK - ADDED EXTRA LEVEL:
void ShowLevelMenu() {
//ovdje inicijalizujemo display
display.cls(); // brišemo prethodno
display.background(Black);
display.foreground(White);
display.locate(80, 50);
cls(); // brišemo prethodno
background(Black);
foreground(White);
locate(80, 50);
printf("LEVEL 1");
display.locate(80, 120);
locate(80, 120);
printf("LEVEL 2");
display.locate(80, 190);
locate(80, 190);
printf("LEVEL 3");
display.locate(80, 260);
locate(80, 260);
printf("LEVEL 4");
DrawCursor(White, level);
}
//////// PORTAPACK
//////// PORTAPACK - KLUDGED FOR BUTTONS VS JOYSTICK:
//////// PORTAPACK - USE BUTTONS VS JOYSTICK:
void ReadJoystickForLevel(){
unsigned char old = level;
if(but_UP){
// upBoundary = 4;
(level == 0) ? level = 3 : level--;
}
else if(but_DOWN){
//ne radi ona prethodna varijanta jer % vraća i negastivni rezultat
//to što ne koristimo unsigned tip ne pomaže jer će doći do overflow-a
// downBoundary = 2;
level = (level + 1) % 4;
}
else {
// downBoundary = 1;
// upBoundary = 5;
}
DrawCursor(Black, old); //na prethodni level popunimo bojom pozadine
DrawCursor(White, level); //na novi level popunimo bijelom bojom - pozadina je crna
//koristio sam fillrect, jer njega svakako moramo koristiti, jer možda budemo morali da brišemo fillcircle iz biblioteke
@@ -169,11 +160,11 @@ main();
void StartGame()
{
display.cls(); // brišemo ShowLevelMenu
display.background(White);
display.foreground(Black);
display.fillrect(0, 0, 160, 320, White);
display.fillrect(160, 0, 240, 320, Black); //dio za prikazivanje rezultata će biti crni pravougaonik, a tabla je bijeli
cls(); // brišemo ShowLevelMenu
background(White);
foreground(Black);
fillrect(0, 0, 160, 320, White);
fillrect(160, 0, 240, 320, Black); //dio za prikazivanje rezultata će biti crni pravougaonik, a tabla je bijeli
ShowScore();
}
@@ -206,34 +197,34 @@ void PutBorders(short x, short y) {
for(int i = x - 1; i <= x + 1; i++) {
for(int j = y - 1; j <= y + 1; j++) {
if(i < 0 || i > 9 || j < 0 || j > 19 || board[j][i] == 0) continue;
display.rect(i * DIMENSION, j * DIMENSION, (i + 1) * DIMENSION, (j + 1) * DIMENSION, Black);
rect(i * DIMENSION, j * DIMENSION, (i + 1) * DIMENSION, (j + 1) * DIMENSION, Black);
}
}
}
class Tetromino{
private:
//////// PORTAPACK - ELIMINATED CLASSES DUE TO GLOBAL OBJECT INITIALIZATION ISSUE WITH EXTERNAL APPS:
//class Tetromino{
//private:
short X[4];
short Y[4];
short boardX, boardY;
unsigned char colorIndex;//dodao sam colorIndex zasad, jer nema drugog načina da popunimo matricu sa indeksima boja
//ovo je najbezbolnija varijanta što se memorije tiče
public:
Tetromino(){
//////// PORTAPACK - NOTE - DEFAULT INITIALIZER CODE DOESN'T GET EXECUTED FOR SOME REASON:
unsigned char r = rand() % 7 + 1;
Initialize(r);
//public:
// Tetromino(){
// unsigned char r = rand() % 7 + 1;
// Initialize(r);
// }
void Tetromino(unsigned char c) {
Initialize(c);
}
Tetromino(unsigned char colorIndex) {
Initialize(colorIndex);
}
void Initialize(unsigned char colorIndex) {
Tetromino::colorIndex = colorIndex;
void Initialize(unsigned char c) {
colorIndex = c;
boardX = 0;
boardY = 4; //3,4 ili 5 najbolje da vidimo kad imamo display
copyCoordinates(X, Y, colorIndex - 1);
copyCoordinates(X, Y, c - 1);
}
void Rotate(){
@@ -266,13 +257,9 @@ public:
//stavio sam 16 za početak, možemo se opet skontati na labu
//ovo pretpostavlja da nema margina, mogu se lagano dodati uz neku konstantu kao offset
int upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
display.fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, colors[colorIndex]);
fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, colors[colorIndex]);
//ovo boji granice blokova u crno, možemo skloniti ako ti se ne sviđa
//////// PORTAPACK - HIDE DEFAULT WHITE BLOCK (ALTERNATE KLUDGE FOR TETRONIMO INITIALIZATION CODE NOT RUNNING AT CONSTRUCTION)
if (colorIndex != White)
//////// PORTAPACK
display.rect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
rect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, Black);
}
}
@@ -280,7 +267,7 @@ if (colorIndex != White)
for(int i = 0; i < 4; i++) {
//ista logika kao u DrawFigure, samo popunjavamo sve blokove sa bijelim pravougaonicima
short upperLeftX = (boardX + X[i]) * DIMENSION, upperLeftY = (boardY + Y[i]) * DIMENSION;
display.fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, White);
fillrect( upperLeftY, upperLeftX, upperLeftY + DIMENSION, upperLeftX + DIMENSION, White);
PutBorders(upperLeftY, upperLeftX);
}
}
@@ -295,9 +282,6 @@ if (colorIndex != White)
}
bool MoveDown(char delta = 1){
//////// PORTAPACK - MOVE DEFAULT WHITE BLOCK TO BOTTOM IMMEDIATELY (ALTERNATE KLUDGE FOR TETRONIMO INITIALIZATION CODE NOT RUNNING AT CONSTRUCTION)
if (colorIndex == White) delta = 19;
//////// PORTAPACK
if(!InCollisionDown(delta)){
DeleteFigure();
boardX+=delta;
@@ -384,34 +368,23 @@ if (colorIndex == White) delta = 19;
return false;
}
};
// };
// Tetromino currentTetromino;
Tetromino currentTetromino;
//////// PORTAPACK - KLUDGED FOR BUTTONS VS JOYSTICK:
//////// PORTAPACK - USE BUTTONS VS JOYSTICK, AND ADDED PAUSE FEATURE:
void ReadJoystickForFigure() {
if(but_LEFT) {
// leftBoundary = 2;
currentTetromino.MoveLeft();
MoveLeft();
}
else if(but_RIGHT) {
// rightBoundary = 4;
currentTetromino.MoveRight();
MoveRight();
}
else if(but_UP) {
// downBoundary = 2;
pause_game();
pause_game();
}
else if(but_DOWN) {
// upBoundary = 4;
currentTetromino.SoftDrop();
}
else {
// leftBoundary = 1;
// rightBoundary = 5;
// downBoundary = 1;
// upBoundary = 5;
SoftDrop();
}
}
//////// PORTAPACK
@@ -460,10 +433,10 @@ void UpdateBoard()
board[i][j] = board[i - numberOfLines][j];
board[i - numberOfLines][j] = 0;
short tmp = i - numberOfLines;
display.fillrect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , colors[board[i][j]]); // bojimo novi blok
display.fillrect( j * DIMENSION, tmp * DIMENSION,(j + 1) * DIMENSION, (tmp + 1) * DIMENSION , White);
fillrect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , colors[board[i][j]]); // bojimo novi blok
fillrect( j * DIMENSION, tmp * DIMENSION,(j + 1) * DIMENSION, (tmp + 1) * DIMENSION , White);
if(board[i][j] != 0)
display.rect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , Black);
rect( j * DIMENSION,i * DIMENSION, (j + 1) * DIMENSION , (i + 1) * DIMENSION , Black);
}
}
score += UpdateScore(numberOfLines);
@@ -480,26 +453,23 @@ bool IsOver() {
void ShowGameOverScreen() {
//////// PORTAPACK - SKIP CLS
// display.cls();
// display.background(Black);
// display.foreground(White);
display.background(White);
display.foreground(Black);
// cls();
// background(Black);
// foreground(White);
background(White);
foreground(Black);
//////// PORTAPACK
display.locate(60, 120);
locate(60, 120);
printf("GAME OVER");
display.locate(40, 150);
locate(40, 150);
printf("YOUR SCORE IS %d", score);
wait(5); //ovaj prikaz traje 3s (možemo mijenjati) a nakon toga se ponovo prikazuje meni sa levelima
}
void InitGame() {
if(firstTime) {
//////// PORTAPACK - NOTE - ATTEMPTED WORKAROUND FOR SKIPPED INITIALIZER CODE - BUT ANY OF THESE CRASHES FIRMWARE AT POWER-UP EVEN IF THERE'S NO TETRIS APP INSTALLED:
// currentTetromino = Tetromino(rand() % 7 + 1); // TEST #1
// currentTetromino.Initialize(rand() % 7 + 1); // TEST #2
//////// PORTAPACK
currentTetromino.DrawFigure();
Tetromino(rand() % 7 + 1);
DrawFigure();
nextFigure = rand() % 7 + 1;
ShowNextFigure();
firstTime = false;
@@ -508,13 +478,13 @@ void InitGame() {
void PlayGame(){
InitGame();
if(!currentTetromino.MoveDown()){
currentTetromino.OnAttached();
if(!MoveDown()){
OnAttached();
UpdateBoard();
ShowScore();
currentTetromino = Tetromino(nextFigure);
currentTetromino.DrawFigure();
Tetromino(nextFigure);
DrawFigure();
nextFigure = rand() % 7 + 1;
ShowNextFigure();
if(IsOver()) {
@@ -531,7 +501,7 @@ void PlayGame(){
void OnTasterPressed(){
if(debounceTaster.read_ms() > 200) {
if(gameStarted){
currentTetromino.Rotate();
Rotate();
}
else{
joystick.detach();
@@ -568,7 +538,7 @@ return 0;
void pause_game() {
game.detach();
joystick.detach();
display.locate(180, 200);
locate(180, 200);
printf("PAUSED");
while ((get_switches_state().to_ulong() & 0x10) == 0); // wait for SELECT button to resume
printf(" ");
+21
View File
@@ -1,3 +1,24 @@
/*
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_tetris.hpp"
namespace ui::external_app::tetris {
+22 -3
View File
@@ -24,6 +24,9 @@
#include "utility.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
uint8_t Debounce::state() {
uint8_t v = state_to_report_;
simulated_pulse_ = false;
@@ -154,19 +157,35 @@ uint8_t EncoderDebounce::state() {
return state_;
}
uint8_t EncoderDebounce::rotation_rate() {
return last_rotation_rate_;
}
// Returns TRUE if encoder position phase bits changed (after debouncing)
bool EncoderDebounce::feed(const uint8_t phase_bits) {
history_ = (history_ << 2) | phase_bits;
// Has input been constant for 4 ticks? (phase_bits * 01010101b should be 0x00, 0x55, 0xAA, or 0xFF)
if (history_ == (phase_bits * 0x55)) {
// If both inputs have been stable for the last 4 ticks, history_ should equal 0x00, 0x55, 0xAA, or 0xFF.
uint8_t expected_stable_history = phase_bits * 0b01010101;
// But, checking for equal seems to cause issues with at least 1 user's encoder, so we're treating the input
// as "stable" if at least ONE input bit is consistent for 4 ticks...
uint8_t diff = (history_ ^ expected_stable_history);
if (((diff & 0b01010101) == 0) || ((diff & 0b10101010) == 0)) {
// Has the debounced input value changed?
if (state_ != phase_bits) {
state_ = phase_bits;
// Rate multiplier is for larger delta increments when dial is rotated rapidly.
last_rotation_rate_ = rotation_rate_downcounter_;
rotation_rate_downcounter_ = portapack::persistent_memory::encoder_rate_multiplier();
return true;
}
}
// Unstable input, or no change
// Unstable input, or no change.
// Decrement rotation rate detector once per timer tick.
if (rotation_rate_downcounter_ > 1)
rotation_rate_downcounter_--;
return false;
}
+6
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -70,10 +71,15 @@ class EncoderDebounce {
uint8_t state(); // returns debounced phase bits from encoder
uint8_t rotation_rate(); // returns last rotation rate
private:
uint8_t history_{0}; // shift register of previous reads from encoder
uint8_t state_{0}; // actual encoder output state (after debounce logic)
uint8_t last_rotation_rate_{1};
uint8_t rotation_rate_downcounter_{1}; // down-counter to estimate rotation speed
};
#endif /*__DEBOUNCE_H__*/
+2 -1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -63,7 +64,7 @@ int_fast8_t Encoder::update(const uint_fast8_t phase_bits) {
// Require 2 state changes in same direction to register movement -- for additional level of contact switch debouncing
if (direction == prev_direction) {
if ((sensitivity_map[portapack::persistent_memory::config_encoder_dial_sensitivity()] & (1 << state)) == 0)
if ((sensitivity_map[portapack::persistent_memory::encoder_dial_sensitivity()] & (1 << state)) == 0)
return 0;
return direction;
}
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+2
View File
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* copyleft (ɔ) 2023 zxkmm under GPL license
* Copyright (C) 2023 u-foka
*
* This file is part of PortaPack.
*
+2
View File
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* copyleft (ɔ) 2023 zxkmm under GPL license
* Copyright (C) 2023 u-foka
*
* This file is part of PortaPack.
*
+29 -9
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -27,8 +28,10 @@ bool WAVFileReader::open(const std::filesystem::path& path) {
size_t i = 0;
char ch;
const uint8_t tag_INAM[4] = {'I', 'N', 'A', 'M'};
const uint8_t tag_data[4] = {'d', 'a', 't', 'a'};
struct data_t data_header;
char title_buffer[32]{0};
uint32_t riff_size, data_end, title_size;
uint32_t riff_size, inam_search_start, title_size;
size_t search_limit = 0;
// Already open ?
@@ -45,17 +48,34 @@ bool WAVFileReader::open(const std::filesystem::path& path) {
auto error = file_.open(path);
if (!error.is_valid()) {
file_.read((void*)&header, sizeof(header)); // Read header (RIFF and WAVE)
if (!file_.read((void*)&header, sizeof(header)).is_ok()) // Read header (RIFF and WAVE)
return false;
// TODO: Work needed here to process RIFF file format correctly, i.e. properly skip over LIST & INFO chunks
riff_size = header.cksize + 8;
data_start = header.fmt.cksize + 28;
data_size_ = header.data.cksize;
data_end = data_start + data_size_ + 1;
// Assuming here that RIFF & WAV & fmt chunk ID's are all correct...
riff_size = 8 + header.cksize;
// check for the "data" chunk ID
if (memcmp(header.data.ckID, tag_data, 4) == 0) {
data_start = 20 + header.fmt.cksize + 8;
data_size_ = header.data.cksize;
inam_search_start = data_start + data_size_;
} else {
// data header wasn't where we guessed; skip over one unexpected chunk (perhaps LIST/INFO/INAM)
inam_search_start = 20 + header.fmt.cksize;
file_.seek(20 + header.fmt.cksize + 8 + header.data.cksize);
if (!file_.read((void*)&data_header, sizeof(data_header)).is_ok())
return false;
if (memcmp(data_header.ckID, tag_data, 4) == 0) {
data_start = 20 + header.fmt.cksize + 8 + header.data.cksize + 8;
data_size_ = data_header.cksize;
} else
return false;
}
// Look for INAM (title) tag
if (data_end < riff_size) {
file_.seek(data_end);
if (inam_search_start < riff_size) {
file_.seek(inam_search_start);
while (file_.read((void*)&ch, 1).is_ok()) {
if (ch == tag_INAM[i++]) {
if (i == 4) {
+2 -1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -166,7 +167,7 @@ static bool encoder_update(const uint8_t raw) {
}
static bool encoder_read() {
auto delta = encoder.update(encoder_debounce.state());
auto delta = encoder.update(encoder_debounce.state()) * encoder_debounce.rotation_rate();
if (injected_encoder > 0) {
if (injected_encoder == 1) delta = -1;
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+21 -14
View File
@@ -162,6 +162,8 @@ static void event_loop() {
}
int main(void) {
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
if (config_mode_should_enter()) {
config_mode_clear();
config_mode_run();
@@ -169,25 +171,30 @@ int main(void) {
config_mode_set();
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
if (portapack::init()) {
portapack::display.init();
config_mode_clear();
switch (portapack::init()) {
case portapack::init_status_t::INIT_HACKRF_CPLD_FAILED:
portapack::init_error = "HACKRF CPLD FAILED";
[[fallthrough]];
// sdcStart(&SDCD1, nullptr); // Commented out as now happens in portapack.cpp
case portapack::init_status_t::INIT_SUCCESS:
// controls_init(); // Commented out as now happens in portapack.cpp
lcd_frame_sync_configure();
rtc_interrupt_enable();
config_mode_clear();
event_loop();
lcd_frame_sync_configure();
rtc_interrupt_enable();
sdcDisconnect(&SDCD1);
sdcStop(&SDCD1);
event_loop();
portapack::shutdown();
} else {
config_mode_clear();
sdcDisconnect(&SDCD1);
sdcStop(&SDCD1);
portapack::shutdown();
break;
case portapack::init_status_t::INIT_NO_PORTAPACK:
case portapack::init_status_t::INIT_PORTAPACK_CPLD_FAILED:
config_mode_clear();
break;
}
m4_init(portapack::spi_flash::image_tag_hackrf, portapack::memory::map::m4_code_hackrf, true);
+201 -131
View File
@@ -28,6 +28,7 @@
#include "hackrf_hal.hpp"
#include "hackrf_gpio.hpp"
using namespace hackrf::one;
#include "jtag_target_gpio.hpp"
#include "clock_manager.hpp"
#include "event_m0.hpp"
@@ -50,9 +51,12 @@ using asahi_kasei::ak4951::AK4951;
#include "file.hpp"
#include "sd_card.hpp"
#include "string_format.hpp"
#include "bitmap.hpp"
namespace portapack {
const char* init_error = nullptr;
portapack::IO io{
portapack::gpio_dir,
portapack::gpio_lcd_rdx,
@@ -172,50 +176,21 @@ constexpr I2CConfig i2c_config_fast_clock{
enum class PortaPackModel {
R1_20150901,
R2_20170522,
AGM,
AUTODETECT,
};
static bool save_config(int8_t value) {
persistent_memory::set_config_cpld(value);
if (sd_card::status() == sd_card::Status::Mounted) {
ensure_directory("/hardware");
File file;
auto sucess = file.create("/hardware/settings.txt");
if (!sucess.is_valid()) {
file.write_line(to_string_dec_uint(value));
}
}
portapack::persistent_memory::cache::persist();
return true;
}
int read_file(std::string name) {
std::string return_string = "";
File file;
auto success = file.open(name);
if (!success.is_valid()) {
char one_char[1];
for (size_t pointer = 0; pointer < file.size(); pointer++) {
file.seek(pointer);
file.read(one_char, 1);
return_string += one_char[0];
}
return std::stoi(return_string);
}
return -1;
}
static int load_config() {
static Optional<int> config_value;
if (!config_value.is_valid()) {
int8_t value = portapack::persistent_memory::config_cpld();
if ((value <= 0 || value >= 5) && sd_card::status() == sd_card::Status::Mounted) {
int data = read_file("/hardware/settings.txt");
if (data != -1) {
config_value = data;
}
} else {
config_value = value;
}
config_value = value;
}
return config_value.value();
}
@@ -224,39 +199,49 @@ static PortaPackModel portapack_model() {
static Optional<PortaPackModel> model;
if (!model.is_valid()) {
const auto switches_state = get_switches_state();
// Only save config if no other multi key boot action is triggered (like pmem reset)
if (switches_state.count() == 1) {
if (switches_state[(size_t)ui::KeyEvent::Up]) {
jtag::GPIOTarget target{
portapack::gpio_cpld_tck,
portapack::gpio_cpld_tms,
portapack::gpio_cpld_tdi,
portapack::gpio_cpld_tdo};
jtag::JTAG jtag{target};
portapack::cpld::CPLD cpld{jtag};
cpld.reset();
cpld.run_test_idle();
uint32_t idcode = cpld.get_idcode();
if (idcode == 0x25610) {
model = PortaPackModel::AGM;
} else {
const auto switches_state = swizzled_switches();
// chDbgPanic(to_string_hex((uint32_t)switches_state.count(), 8).c_str());
// Only save config if no other multi key boot action is triggered (like pmem reset)
if (((switches_state >> (size_t)ui::KeyEvent::Up) & 1) == 1) {
save_config(1);
// model = PortaPackModel::R2_20170522; // Commented these out as they should be set down below anyway
} else if (switches_state[(size_t)ui::KeyEvent::Down]) {
} else if (((switches_state >> (size_t)ui::KeyEvent::Down) & 1) == 1) {
save_config(2);
// model = PortaPackModel::R1_20150901;
} else if (switches_state[(size_t)ui::KeyEvent::Left]) {
} else if (((switches_state >> (size_t)ui::KeyEvent::Left) & 1) == 1) {
save_config(3);
// model = PortaPackModel::R1_20150901;
} else if (switches_state[(size_t)ui::KeyEvent::Right]) {
} else if (((switches_state >> (size_t)ui::KeyEvent::Right) & 1) == 1) {
save_config(4);
// model = PortaPackModel::R2_20170522;
} else if (switches_state[(size_t)ui::KeyEvent::Select]) {
} else if (((switches_state >> (size_t)ui::KeyEvent::Select) & 1) == 1) {
save_config(0);
}
}
if (load_config() == 1) {
model = PortaPackModel::R2_20170522;
} else if (load_config() == 2) {
model = PortaPackModel::R1_20150901;
} else if (load_config() == 3) {
model = PortaPackModel::R1_20150901;
} else if (load_config() == 4) {
model = PortaPackModel::R2_20170522;
} else {
if (audio_codec_wm8731.detected()) {
model = PortaPackModel::R1_20150901; // H1R1
if (load_config() == 1) {
model = PortaPackModel::R2_20170522;
} else if (load_config() == 2) {
model = PortaPackModel::R1_20150901;
} else if (load_config() == 3) {
model = PortaPackModel::R1_20150901;
} else if (load_config() == 4) {
model = PortaPackModel::R2_20170522;
} else {
model = PortaPackModel::R2_20170522; // H1R2, H2, H2+
model = PortaPackModel::AUTODETECT;
}
}
}
@@ -343,6 +328,129 @@ static void shutdown_base() {
clock_manager.shutdown();
}
static void set_cpu_clock_speed() {
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
* core clock speed to the 110 - 204MHz range.
*/
/* Step into the 90-110MHz M4 clock range */
/* OG:
* Fclkin = 40M
* /N=2 = 20M = PFDin
* Fcco = PFDin * (M=10) = 200M
* r9:
* Fclkin = 10M
* /N=1 = 10M = PFDin
* Fcco = PFDin * (M=20) = 200M
* Fclk = Fcco / (2*(P=1)) = 100M
*/
cgu::pll1::ctrl({
.pd = 1,
.bypass = 0,
.fbsel = 0,
.direct = 0,
.psel = 0,
.autoblock = 1,
.nsel = hackrf_r9 ? 0UL : 1UL,
.msel = hackrf_r9 ? 19UL : 9UL,
.clk_sel = cgu::CLK_SEL::GP_CLKIN,
});
cgu::pll1::enable();
while (!cgu::pll1::is_locked())
;
set_clock_config(clock_config_pll1_step);
/* Delay >50us at 90-110MHz clock speed */
volatile uint32_t delay = 1400;
while (delay--)
;
set_clock_config(clock_config_pll1);
/* Remove /2P divider from PLL1 output to achieve full speed */
cgu::pll1::direct();
}
static void draw_splash_screen_icon(int16_t n, const ui::Bitmap& bitmap) {
ui::Painter painter;
painter.draw_bitmap(
{portapack::display.width() / 2 - 8 - 40 + (n * 20), portapack::display.height() / 2 - 8 + 40},
bitmap,
ui::Color::white(),
ui::Color::black());
}
static bool is_portapack_present() {
systime_t timeout = 50;
uint8_t wm8731_reset_command[] = {0x0f, 0x00};
if (i2c0.transmit(0x1a /* wm8731 */, wm8731_reset_command, 2, timeout) == false) {
audio_codec_ak4951.reset();
uint8_t ak4951_init_command[] = {0x00, 0x00};
i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout);
chThdSleepMilliseconds(10);
if (i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout) == false) {
shutdown_base();
return false;
}
}
return true;
}
static bool check_portapack_cpld() {
switch (portapack_model()) {
case PortaPackModel::AUTODETECT: {
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_autodetect(
portapack::cpld::rev_20150901::config, portapack::cpld::rev_20170522::config);
if (result != portapack::cpld::CpldUpdateStatus::Success) {
shutdown_base();
return false;
}
} break;
case PortaPackModel::R1_20150901:
case PortaPackModel::R2_20170522: {
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
if (result == portapack::cpld::CpldUpdateStatus::Program_failed) {
chThdSleepMilliseconds(10);
// Mode left (R1) and right (R2,H2,H2+) bypass going into hackrf mode after failing CPLD update
// Mode center (autodetect), up (R1) and down (R2,H2,H2+) will go into hackrf mode after failing CPLD update
if (load_config() != 3 /* left */ && load_config() != 4 /* right */) {
shutdown_base();
return false;
}
}
} break;
case PortaPackModel::AGM:
// the AGM devices are always factory flashed. so do nothing
break;
}
return true;
}
static void initialize_boot_splash_screen() {
ui::Painter painter;
portapack::display.init();
painter.fill_rectangle(
{0, 0, portapack::display.width(), portapack::display.height()},
ui::Color::black());
chThdSleepMilliseconds(17);
portapack::backlight()->on();
painter.draw_bitmap(
{portapack::display.width() / 2 - 40, portapack::display.height() / 2 - 8},
ui::bitmap_titlebar_image,
ui::Color::white(),
ui::Color::black());
}
/* Clock scheme after exiting bootloader in SPIFI mode:
*
* XTAL_OSC = powered down
@@ -389,28 +497,29 @@ static void shutdown_base() {
* everything else = IRC
*/
bool init() {
init_status_t init() {
set_idivc_base_clocks(cgu::CLK_SEL::IDIVC);
i2c0.start(i2c_config_boot_clock);
// Keeping this here for now incase we need to revert
// if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
// shutdown_base();
// return false;
// }
// if( !hackrf::cpld::load_sram() ) {
// chSysHalt();
// }
chThdSleepMilliseconds(100);
configure_pins_portapack();
portapack::io.init();
persistent_memory::cache::init();
const auto switches_state = swizzled_switches() & (~(0xC0 | 0x80));
bool lcd_fast_setup = switches_state == 0 && portapack::display.read_display_status();
if (lcd_fast_setup) {
initialize_boot_splash_screen();
} else {
if (check_portapack_cpld() == false)
return init_status_t::INIT_PORTAPACK_CPLD_FAILED;
}
/* Cache some configuration data from persistent memory. */
persistent_memory::cache::init();
rtc_time::dst_init();
chThdSleepMilliseconds(10);
@@ -423,48 +532,10 @@ bool init() {
set_clock_config(clock_config_irc);
cgu::pll1::disable();
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
* core clock speed to the 110 - 204MHz range.
*/
set_cpu_clock_speed();
/* Step into the 90-110MHz M4 clock range */
/* OG:
* Fclkin = 40M
* /N=2 = 20M = PFDin
* Fcco = PFDin * (M=10) = 200M
* r9:
* Fclkin = 10M
* /N=1 = 10M = PFDin
* Fcco = PFDin * (M=20) = 200M
* Fclk = Fcco / (2*(P=1)) = 100M
*/
cgu::pll1::ctrl({
.pd = 1,
.bypass = 0,
.fbsel = 0,
.direct = 0,
.psel = 0,
.autoblock = 1,
.nsel = hackrf_r9 ? 0UL : 1UL,
.msel = hackrf_r9 ? 19UL : 9UL,
.clk_sel = cgu::CLK_SEL::GP_CLKIN,
});
cgu::pll1::enable();
while (!cgu::pll1::is_locked())
;
set_clock_config(clock_config_pll1_step);
/* Delay >50us at 90-110MHz clock speed */
volatile uint32_t delay = 1400;
while (delay--)
;
set_clock_config(clock_config_pll1);
/* Remove /2P divider from PLL1 output to achieve full speed */
cgu::pll1::direct();
if (lcd_fast_setup)
draw_splash_screen_icon(0, ui::bitmap_icon_memory);
usb_serial.initialize();
@@ -472,18 +543,11 @@ bool init() {
chThdSleepMilliseconds(10);
/* Check if portapack is attached by checking if any of the two audio chips is present. */
systime_t timeout = 50;
uint8_t wm8731_reset_command[] = {0x0f, 0x00};
if (i2c0.transmit(0x1a /* wm8731 */, wm8731_reset_command, 2, timeout) == false) {
audio_codec_ak4951.reset();
uint8_t ak4951_init_command[] = {0x00, 0x00};
i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout);
chThdSleepMilliseconds(10);
if (i2c0.transmit(0x12 /* ak4951 */, ak4951_init_command, 2, timeout) == false) {
shutdown_base();
return false;
}
}
if (lcd_fast_setup == false && is_portapack_present() == false)
return init_status_t::INIT_NO_PORTAPACK;
if (lcd_fast_setup)
draw_splash_screen_icon(1, ui::bitmap_icon_remote);
touch::adc::init();
controls_init();
@@ -499,20 +563,19 @@ bool init() {
chThdSleepMilliseconds(10);
portapack::cpld::CpldUpdateStatus result = portapack::cpld::update_if_necessary(portapack_cpld_config());
if (result == portapack::cpld::CpldUpdateStatus::Program_failed) {
chThdSleepMilliseconds(10);
// Mode left (R1) and right (R2,H2,H2+) bypass going into hackrf mode after failing CPLD update
// Mode center (autodetect), up (R1) and down (R2,H2,H2+) will go into hackrf mode after failing CPLD update
if (load_config() != 3 /* left */ && load_config() != 4 /* right */) {
shutdown_base();
return false;
}
if (lcd_fast_setup)
draw_splash_screen_icon(2, ui::bitmap_icon_sd);
init_status_t return_code = init_status_t::INIT_SUCCESS;
if (!hackrf::cpld::load_sram()) {
if (lcd_fast_setup)
chDbgPanic("HACKRF CPLD FAILED");
return_code = init_status_t::INIT_HACKRF_CPLD_FAILED;
}
if (!hackrf::cpld::load_sram()) {
chSysHalt();
}
if (lcd_fast_setup)
draw_splash_screen_icon(3, ui::bitmap_icon_hackrf);
chThdSleepMilliseconds(10); // This delay seems to solve white noise audio issues
@@ -523,7 +586,14 @@ bool init() {
audio::init(portapack_audio_codec());
return true;
if (lcd_fast_setup)
draw_splash_screen_icon(4, ui::bitmap_icon_speaker);
else {
portapack::display.init();
portapack::backlight()->on();
}
return return_code;
}
void shutdown(const bool leave_screen_on) {
+10 -1
View File
@@ -41,6 +41,15 @@
* guardrails on setting properties. */
namespace portapack {
enum class init_status_t {
INIT_SUCCESS,
INIT_NO_PORTAPACK,
INIT_PORTAPACK_CPLD_FAILED,
INIT_HACKRF_CPLD_FAILED,
};
extern const char* init_error;
extern portapack::IO io;
extern lcd::ILI9341 display;
@@ -65,7 +74,7 @@ extern TemperatureLogger temperature_logger;
void set_antenna_bias(const bool v);
bool get_antenna_bias();
bool init();
init_status_t init();
void shutdown(const bool leave_screen_on = false);
void setEventDispatcherToUSBSerial(EventDispatcher* evt);
+3 -2
View File
@@ -116,8 +116,9 @@ void set_direction(const rf::Direction new_direction) {
/* TODO: Refactor all the various "Direction" enumerations into one. */
/* TODO: Only make changes if direction changes, but beware of clock enabling. */
// Prevents ghosting when switching back to RX from TX mode.
hackrf::cpld::load_sram_no_verify();
// That below code line , was used to prevent RX interf ghosting when switching back to RX from any TX mode, but in recent code. it seems not necessary.
// Deleting that load_sram_no_verify() (or the original , load_sram() ), solves random TX swap I/Q problem in H1R1 , others OK- (and no side effects to all).
// hackrf::cpld::load_sram_no_verify(); // After commit "removed the use of the hackrf cpld eeprom #1732", in a H1R1, Mic App wrong SSB TX with random USB/LSB change.
direction = new_direction;
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+9 -2
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2019 Elia Yehuda (z4ziggy)
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -126,6 +127,7 @@ void BtnGridView::add_item(GridItem new_item) {
void BtnGridView::update_items() {
size_t i = 0;
Color bg_color = portapack::persistent_memory::menu_color();
if ((menu_items.size()) > (displayed_max + offset)) {
more = true;
@@ -146,6 +148,7 @@ void BtnGridView::update_items() {
item->set_text(menu_items[i + offset].text);
item->set_bitmap(menu_items[i + offset].bitmap);
item->set_color(menu_items[i + offset].color);
item->set_bg_color(bg_color);
item->on_select = menu_items[i + offset].on_select;
item->set_dirty();
}
@@ -170,15 +173,19 @@ bool BtnGridView::set_highlighted(int32_t new_value) {
if (((uint32_t)new_value > offset) && ((new_value - offset) >= displayed_max)) {
// Shift BtnGridView up
highlighted_item = new_value;
// rounding up new offset to next multiple of rows
offset = new_value - displayed_max + rows_;
offset -= (offset % rows_);
update_items();
set_dirty();
// refresh whole screen (display flickers) only if scrolling last row up and a blank button is needed at the bottom
if ((new_value + rows_ >= item_count) && (item_count % rows_) != 0)
set_dirty();
} else if ((uint32_t)new_value < offset) {
// Shift BtnGridView down
highlighted_item = new_value;
offset = (new_value / rows_) * rows_;
update_items();
set_dirty();
// no need to set_dirty() here since all buttons have been repainted
} else {
// Just update highlight
highlighted_item = new_value;
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+6
View File
@@ -86,6 +86,12 @@ const Style Styles::bg_blue{
.foreground = Color::white(),
};
const Style Styles::bg_dark_blue{
.font = font::fixed_8x16,
.background = Color::dark_blue(),
.foreground = Color::white(),
};
const Style Styles::light_grey{
.font = font::fixed_8x16,
.background = Color::black(),
+3
View File
@@ -58,6 +58,9 @@ class Styles {
/* Blue background. */
static const Style bg_blue;
/* Dark blue background. */
static const Style bg_dark_blue;
/* Light grey foreground. */
static const Style light_grey;
+16
View File
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 u-foka
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
*
@@ -327,6 +329,15 @@ SystemStatusView::SystemStatusView(
refresh();
};
button_fake_brightness.on_select = [this](ImageButton&) {
set_dirty();
pmem::toggle_fake_brightness_level();
refresh();
if (nullptr != parent()) {
parent()->set_dirty(); // The parent of NavigationView shal be the SystemView
}
};
button_bias_tee.on_select = [this](ImageButton&) {
this->on_bias_tee();
};
@@ -369,6 +380,8 @@ void SystemStatusView::refresh() {
// Display "Disable speaker" icon only if AK4951 Codec which has separate speaker/headphone control
if (audio::speaker_disable_supported() && !pmem::ui_hide_speaker()) status_icons.add(&toggle_speaker);
if (!pmem::ui_hide_fake_brightness()) status_icons.add(&button_fake_brightness);
if (!pmem::ui_hide_sd_card()) status_icons.add(&sd_card_status_view);
status_icons.update_layout();
@@ -390,6 +403,9 @@ void SystemStatusView::refresh() {
button_converter.set_bitmap(pmem::config_updown_converter() ? &bitmap_icon_downconvert : &bitmap_icon_upconvert);
button_converter.set_foreground(pmem::config_converter() ? Color::red() : Color::light_grey());
// Fake Brightness
button_fake_brightness.set_foreground(pmem::apply_fake_brightness() ? Color::green() : Color::light_grey());
set_dirty();
}
+8 -4
View File
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 u-foka
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
*
@@ -264,6 +266,12 @@ class SystemStatusView : public View {
Color::light_grey(),
Color::dark_grey()};
ImageButton button_fake_brightness{
{0, 0, 2 * 8, 1 * 16},
&bitmap_icon_brightness,
Color::green(),
Color::dark_grey()};
SDCardStatusView sd_card_status_view{
{0, 0 * 16, 2 * 8, 1 * 16}};
@@ -312,10 +320,6 @@ class BMPView : public View {
void focus() override;
private:
Text text_info{
{4 * 8, 284, 20 * 8, 16},
"Version " VERSION_STRING};
Button button_done{
{240, 0, 1, 1},
""};
+44 -12
View File
@@ -199,7 +199,7 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) {
std::array<ui::ColorRGB888, ui::screen_width> row;
portapack::display.read_pixels({0, i, ui::screen_width, 1}, row);
for (int px = 0; px < ui::screen_width; px += 5) {
char buffer[5 * 3 * 2];
char buffer[5 * 3 * 2 + 1];
sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", row[px].r, row[px].g, row[px].b, row[px + 1].r, row[px + 1].g, row[px + 1].b, row[px + 2].r, row[px + 2].g, row[px + 2].b, row[px + 3].r, row[px + 3].g, row[px + 3].b, row[px + 4].r, row[px + 4].g, row[px + 4].b);
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 5 * 3 * 2);
}
@@ -211,6 +211,7 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) {
chprintf(chp, "ok\r\n");
}
// calculates the 1 byte rgb value, and add 32 to it, so it can be a printable character.
static char getChrFromRgb(uint8_t r, uint8_t g, uint8_t b) {
uint8_t chR = r >> 6; // 3bit
uint8_t chG = g >> 6; // 3bit
@@ -220,26 +221,36 @@ static char getChrFromRgb(uint8_t r, uint8_t g, uint8_t b) {
return res;
}
// keep track of a buffer, and sends only if full. not only line by line
static void screenbuffer_helper_add(BaseSequentialStream* chp, char* buffer, size_t& wp, char ch) {
buffer[wp++] = ch;
if (wp > USBSERIAL_BUFFERS_SIZE - 1) {
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, USBSERIAL_BUFFERS_SIZE);
wp = 0;
}
}
// sends only 1 byte (printable only) per pixel, so around 96 colors
static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv[]) {
(void)argc;
(void)argv;
auto evtd = getEventDispatcherInstance();
evtd->enter_shell_working_mode();
char buffer[USBSERIAL_BUFFERS_SIZE];
size_t wp = 0;
for (int y = 0; y < ui::screen_height; y++) {
std::array<ui::ColorRGB888, ui::screen_width> row;
portapack::display.read_pixels({0, y, ui::screen_width, 1}, row);
char buffer[242];
for (int i = 0; i < 240; ++i) {
buffer[i] = getChrFromRgb(row[i].r, row[i].g, row[i].b);
screenbuffer_helper_add(chp, buffer, wp, getChrFromRgb(row[i].r, row[i].g, row[i].b));
}
buffer[240] = '\r';
buffer[241] = '\n';
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 242);
screenbuffer_helper_add(chp, buffer, wp, '\r');
screenbuffer_helper_add(chp, buffer, wp, '\n');
}
if (wp > 0) {
// send remaining
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, wp);
}
evtd->exit_shell_working_mode();
chprintf(chp, "\r\nok\r\n");
}
@@ -911,13 +922,33 @@ static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
}
static void cmd_gotorientation(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotorientation <angle>\r\n";
if (argc != 1) {
const char* usage = "usage: gotorientation <angle> [tilt]\r\n";
if (argc != 1 && argc != 2) {
chprintf(chp, usage);
return;
}
uint16_t angle = strtol(argv[0], NULL, 10);
OrientationDataMessage msg{angle};
int16_t tilt = 400;
if (argc >= 2) tilt = strtol(argv[1], NULL, 10);
OrientationDataMessage msg{angle, tilt};
EventDispatcher::send_message(msg);
chprintf(chp, "ok\r\n");
}
static void cmd_gotenv(BaseSequentialStream* chp, int argc, char* argv[]) {
const char* usage = "usage: gotenv <temperature> [humidity] [pressure] [light]\r\n";
if (argc < 1 || argc > 4) {
chprintf(chp, usage);
return;
}
float temp = atof(argv[0]);
float humi = 0;
float pressure = 0;
uint16_t light = 0;
if (argc > 1) humi = atof(argv[1]);
if (argc > 2) pressure = atof(argv[2]);
if (argc > 3) light = strtol(argv[3], NULL, 10);
EnvironmentDataMessage msg{temp, humi, pressure, light};
EventDispatcher::send_message(msg);
chprintf(chp, "ok\r\n");
}
@@ -1044,6 +1075,7 @@ static const ShellCommand commands[] = {
{"appstart", cmd_appstart},
{"gotgps", cmd_gotgps},
{"gotorientation", cmd_gotorientation},
{"gotenv", cmd_gotenv},
{"sysinfo", cmd_sysinfo},
{"radioinfo", cmd_radioinfo},
{"pmemreset", cmd_pmemreset},
@@ -26,6 +26,8 @@
#include "string_format.hpp"
#include <cstring>
#include "crc.hpp"
static File* shell_file = nullptr;
static bool report_on_error(BaseSequentialStream* chp, File::Error& error) {
@@ -97,7 +99,7 @@ void cmd_sd_mkdir(BaseSequentialStream* chp, int argc, char* argv[]) {
auto path = path_from_string8(argv[0]);
if (!std::filesystem::is_directory(path)) {
if (std::filesystem::is_directory(path)) {
chprintf(chp, "directory already exists.\r\n");
return;
}
@@ -371,3 +373,34 @@ void cmd_sd_write_binary(BaseSequentialStream* chp, int argc, char* argv[]) {
chprintf(chp, "ok\r\n");
}
void cmd_sd_crc32(BaseSequentialStream* chp, int argc, char* argv[]) {
if (argc != 1) {
chprintf(chp, "usage: crc32 <path>\r\n");
return;
}
auto path = path_from_string8(argv[0]);
File* crc_file = new File();
auto error = crc_file->open(path, true, false);
if (report_on_error(chp, error)) return;
uint8_t buffer[64];
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
while (true) {
auto bytes_read = crc_file->read(buffer, 64);
if (report_on_error(chp, bytes_read)) return;
if (bytes_read.value() > 0) {
crc.process_bytes((void*)buffer, bytes_read.value());
}
if (64 != bytes_read.value()) {
chprintf(chp, "CRC32: 0x%08X\r\n", crc.checksum());
return;
}
}
delete crc_file;
}
@@ -42,6 +42,7 @@ void cmd_sd_read(BaseSequentialStream* chp, int argc, char* argv[]);
void cmd_sd_read_binary(BaseSequentialStream* chp, int argc, char* argv[]);
void cmd_sd_write(BaseSequentialStream* chp, int argc, char* argv[]);
void cmd_sd_write_binary(BaseSequentialStream* chp, int argc, char* argv[]);
void cmd_sd_crc32(BaseSequentialStream* chp, int argc, char* argv[]);
static std::filesystem::path path_from_string8(char* path) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
@@ -62,6 +63,7 @@ static std::filesystem::path path_from_string8(char* path) {
{"ftell", cmd_sd_tell}, \
{"fread", cmd_sd_read}, \
{"frb", cmd_sd_read_binary}, \
{"fwrite", cmd_sd_write}, \
{"fwb", cmd_sd_write_binary}
{"fwrite", cmd_sd_write}, \
{"fwb", cmd_sd_write_binary}, \
{"crc32", cmd_sd_crc32}
// clang-format on
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+122 -2
View File
@@ -23,6 +23,7 @@
#include "hackrf_gpio.hpp"
#include "portapack_hal.hpp"
#include "portapack.hpp"
#include "jtag_target_gpio.hpp"
#include "cpld_max5.hpp"
@@ -30,11 +31,15 @@
#include "portapack_cpld_data.hpp"
#include "hackrf_cpld_data.hpp"
#include "crc.hpp"
#define REV_20150901_CHECKSUM 0xE0EF80FB
#define REV_20170522_CHECKSUM 0xD1BEB722
namespace portapack {
namespace cpld {
CpldUpdateStatus update_if_necessary(
const Config config) {
CpldUpdateStatus update_if_necessary(const Config config) {
jtag::GPIOTarget target{
portapack::gpio_cpld_tck,
portapack::gpio_cpld_tms,
@@ -87,6 +92,121 @@ CpldUpdateStatus update_if_necessary(
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
}
static CpldUpdateStatus enter_maintenance_mode(CPLD& cpld) {
/* Unknown state */
cpld.reset();
cpld.run_test_idle();
/* Run-Test/Idle */
if (!cpld.idcode_ok()) {
return CpldUpdateStatus::Idcode_check_failed;
}
cpld.sample();
cpld.bypass();
cpld.enable();
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
* in passive state.
*/
if (!cpld.silicon_id_ok()) {
return CpldUpdateStatus::Silicon_id_check_failed;
}
return CpldUpdateStatus::Success;
}
static void exit_maintenance_mode(CPLD& cpld) {
cpld.disable();
cpld.bypass();
/* Initiate SRAM reload from flash we just programmed. */
cpld.sample();
cpld.clamp();
cpld.disable();
}
static uint32_t get_firmware_crc(CPLD& cpld) {
CRC<32> crc{0x04c11db7, 0xffffffff, 0xffffffff};
cpld.prepare_read(0x0000);
for (size_t i = 0; i < 3328; i++) {
uint16_t data = cpld.read();
crc.process_byte((data >> 0) & 0xff);
crc.process_byte((data >> 8) & 0xff);
crc.process_byte((data >> 16) & 0xff);
crc.process_byte((data >> 24) & 0xff);
}
cpld.prepare_read(0x0001);
for (size_t i = 0; i < 512; i++) {
uint16_t data = cpld.read();
crc.process_byte((data >> 0) & 0xff);
crc.process_byte((data >> 8) & 0xff);
crc.process_byte((data >> 16) & 0xff);
crc.process_byte((data >> 24) & 0xff);
}
return crc.checksum();
}
CpldUpdateStatus update_autodetect(const Config config_rev_20150901, const Config config_rev_20170522) {
jtag::GPIOTarget target{
portapack::gpio_cpld_tck,
portapack::gpio_cpld_tms,
portapack::gpio_cpld_tdi,
portapack::gpio_cpld_tdo};
jtag::JTAG jtag{target};
CPLD cpld{jtag};
if (portapack::display.read_display_status())
return CpldUpdateStatus::Success; // LCD is ready
CpldUpdateStatus result = enter_maintenance_mode(cpld);
if (result != CpldUpdateStatus::Success)
return result;
uint32_t checksum = get_firmware_crc(cpld);
if (checksum == REV_20170522_CHECKSUM) {
// H2 firmware present
if (!cpld.program(config_rev_20150901.block_0, config_rev_20150901.block_1))
return CpldUpdateStatus::Program_failed;
} else if (checksum == REV_20150901_CHECKSUM) {
// H1 firmware present
if (!cpld.program(config_rev_20170522.block_0, config_rev_20170522.block_1))
return CpldUpdateStatus::Program_failed;
} else {
// no firmware present
if (!cpld.program(config_rev_20150901.block_0, config_rev_20150901.block_1))
return CpldUpdateStatus::Program_failed;
}
exit_maintenance_mode(cpld);
if (portapack::display.read_display_status())
return CpldUpdateStatus::Success; // LCD is ready
if (checksum != REV_20150901_CHECKSUM && checksum != REV_20170522_CHECKSUM) {
// try the other one
CpldUpdateStatus result = enter_maintenance_mode(cpld);
if (result != CpldUpdateStatus::Success)
return result;
if (!cpld.program(config_rev_20170522.block_0, config_rev_20170522.block_1))
return CpldUpdateStatus::Program_failed;
exit_maintenance_mode(cpld);
if (portapack::display.read_display_status())
return CpldUpdateStatus::Success; // LCD is ready
}
return CpldUpdateStatus::Program_failed;
}
} /* namespace cpld */
} /* namespace portapack */
+2 -2
View File
@@ -34,8 +34,8 @@ enum class CpldUpdateStatus {
Program_failed = 3
};
CpldUpdateStatus update_if_necessary(
const Config config);
CpldUpdateStatus update_if_necessary(const Config config);
CpldUpdateStatus update_autodetect(const Config config_rev_20150901, const Config config_rev_20170522);
} /* namespace cpld */
} /* namespace portapack */
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+1
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2023 Mark Thompson
*
* This file is part of PortaPack.
*
+30
View File
@@ -84,6 +84,17 @@ void lcd_wake() {
lcd_display_on();
}
uint32_t lcd_read_display_status() {
io.lcd_data_write_command_and_data(0x09, {});
io.lcd_read_word();
uint32_t value2 = io.lcd_read_word();
uint32_t value3 = io.lcd_read_word();
uint32_t value4 = io.lcd_read_word();
uint32_t value5 = io.lcd_read_word();
return value5 + (value4 << 8) + (value3 << 16) + (value2 << 24);
}
void lcd_init() {
// LCDs are configured for IM[2:0] = 001
// 8080-I system, 16-bit parallel bus
@@ -260,6 +271,25 @@ void lcd_vertical_scrolling_start_address(
} // namespace
bool ILI9341::read_display_status() {
lcd_reset();
uint32_t display_status = lcd_read_display_status();
/* This tries to validate the display_status.
* The value could vary from device to device, so we are less specific here.
* 0xFFFFFEFF was seen when the display was not reachable
* 0x00610000 was seen when the display was reachable
*/
if (display_status > 0x0E000000ULL)
return false;
if (display_status < 0x00000100ULL)
return false;
return true;
}
void ILI9341::init() {
lcd_reset();
lcd_init();
+2
View File
@@ -42,6 +42,8 @@ class ILI9341 {
ILI9341(ILI9341&&) = delete;
void operator=(const ILI9341&) = delete;
bool read_display_status();
void init();
void shutdown();
+25 -2
View File
@@ -120,6 +120,7 @@ class Message {
SubGhzDData = 62,
GPSPosData = 63,
OrientationData = 64,
EnvironmentData = 65,
MAX
};
@@ -1328,11 +1329,33 @@ class GPSPosDataMessage : public Message {
class OrientationDataMessage : public Message {
public:
constexpr OrientationDataMessage(
uint16_t angle = 400)
uint16_t angle = 400,
int16_t tilt = 400)
: Message{ID::OrientationData},
angle{angle} {
angle{angle},
tilt{tilt} {
}
uint16_t angle = 400; //>360 -> no orientation set
int16_t tilt = 400;
};
class EnvironmentDataMessage : public Message {
public:
constexpr EnvironmentDataMessage(
float temperature = 0,
float humidity = 0,
float pressure = 0,
uint16_t light = 0)
: Message{ID::EnvironmentData},
temperature{temperature},
humidity{humidity},
pressure{pressure},
light{light} {
}
float temperature = 0; // celsius
float humidity = 0; // percent (rh)
float pressure = 0; // hpa
uint16_t light = 0; // lux
};
#endif /*__MESSAGE_H__*/
+10
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyleft (ɔ) 2024 zxkmm under GPL license
*
* This file is part of PortaPack.
*
@@ -20,6 +21,7 @@
*/
#include "portapack_io.hpp"
#include "portapack_persistent_memory.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
@@ -75,6 +77,14 @@ void IO::reference_oscillator(const bool enable) {
io_write(1, io_reg);
}
bool IO::get_dark_cover() {
return portapack::persistent_memory::apply_fake_brightness();
}
uint8_t IO::get_brightness() {
return portapack::persistent_memory::fake_brightness_level();
}
uint32_t IO::io_update(const TouchPinsConfig write_value) {
/* Very touchy code to save context of PortaPack data bus while the
* resistive touch pin drive is changed. Order of operations is
+78 -4
View File
@@ -1,5 +1,8 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyleft (ɔ) 2024 zxkmm under GPL license
* Copyright (C) 2024 u-foka
* Copyright (C) 2024 Mark Thompson
*
* This file is part of PortaPack.
*
@@ -30,6 +33,23 @@
#include "gpio.hpp"
#include "ui.hpp"
// #include "portapack_persistent_memory.hpp"
// Darkened pixel bit mask for each possible shift value.
static const uint16_t darken_mask[4] = {
0b1111111111111111, // RrrrrGgggggBbbbb
0b0111101111101111, // 0Rrrr0Ggggg0Bbbb
0b0011100111100111, // 00Rrr00Gggg00Bbb
0b0001100011100011 // 000Rr000Ggg000Bb
};
// To darken, dividing each color level R/G/B by 2^shift.
#define DARKENED_PIXEL(pixel, shift) ((pixel >> shift) & darken_mask[shift])
// To un-darken, multiply each color level by 2^shift (might still be darker that before since some bits may have been lost above).
// This function will only be called when the pixel has previously been darkened, so no masking is needed.
#define UNDARKENED_PIXEL(pixel, shift) (pixel << shift)
namespace portapack {
class IO {
@@ -141,7 +161,10 @@ class IO {
}
}
void lcd_write_pixel(const ui::Color pixel) {
void lcd_write_pixel(ui::Color pixel) {
if (get_dark_cover()) {
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
}
lcd_write_data(pixel.v);
}
@@ -149,13 +172,19 @@ class IO {
return lcd_read_data();
}
void lcd_write_pixels(const ui::Color pixel, size_t n) {
void lcd_write_pixels(ui::Color pixel, size_t n) {
if (get_dark_cover()) {
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
}
while (n--) {
lcd_write_data(pixel.v);
}
}
void lcd_write_pixels_unrolled8(const ui::Color pixel, size_t n) {
void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) {
if (get_dark_cover()) {
pixel.v = DARKENED_PIXEL(pixel.v, get_brightness());
}
auto v = pixel.v;
n >>= 3;
while (n--) {
@@ -203,6 +232,10 @@ class IO {
return switches_raw;
}
bool get_dark_cover();
uint8_t get_brightness();
// TODO: cache the value ^^ & ^ to increaase performance, need a trigger cuz init doesn't work. And since the constructor is constexpr, we can't use with in class var to cache it. maybe cache from outside somewhere and pass it here as argument.
uint32_t io_update(const TouchPinsConfig write_value);
uint32_t lcd_te() {
@@ -314,6 +347,42 @@ class IO {
addr(1); /* Set up for data phase (most likely after a command) */
}
// void high_contrast(ui::Color& pixel, size_t contrast_level_shift) { // TODO
// uint16_t r = (pixel.v >> 11) & 0x1F;
// uint16_t g = (pixel.v >> 5) & 0x3F;
// uint16_t b = pixel.v & 0x1F;
//
// if ((r << contrast_level_shift) > 0x1F) { // should be slightly smaller, need more obverse...
// r = 0x1F;
// } else {
// r = r << contrast_level_shift;
// }
//
// if ((g << contrast_level_shift) > 0x3F) { // same as above
// g = 0x3F;
// } else {
// g = g << contrast_level_shift;
// }
//
// if ((b << contrast_level_shift) > 0x1F) { // same as above
// b = 0x1F;
// } else {
// b = b << contrast_level_shift;
// }
//
// pixel.v = (r << 11) | (g << 5) | b;
// }
//
// void gray_scale(ui::Color& pixel) { // TODO: the blackwhite not looks right....
// uint16_t r = (pixel.v >> 11) & 0x1F;
// uint16_t g = (pixel.v >> 5) & 0x3F;
// uint16_t b = pixel.v & 0x1F;
//
// uint16_t average = (r + g + b) / 3;
//
// pixel.v = (average << 11) | (average << 5) | average;
// }
void lcd_write_data(const uint32_t value) __attribute__((always_inline)) {
// NOTE: Assumes and DIR=0 and ADDR=1 from command phase.
data_write_high(value); /* Drive high byte */
@@ -345,7 +414,12 @@ class IO {
halPolledDelay(18); // 90ns
const auto value_low = data_read();
return (value_high << 8) | value_low;
uint32_t original_value = (value_high << 8) | value_low;
if (get_dark_cover()) {
original_value = UNDARKENED_PIXEL(original_value, get_brightness());
}
return original_value;
}
void io_write(const bool address, const uint_fast16_t value) {

Some files were not shown because too many files have changed in this diff Show More