mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-15 11:02:58 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 409242507c | |||
| 0a8194fa10 | |||
| eaac40df3a | |||
| 58b488b840 | |||
| 1676702a09 | |||
| 3943848add | |||
| 831dbeaab5 | |||
| 49e719ded8 | |||
| c2d2409bff | |||
| 485f57d86b | |||
| 0e6f303eec |
@@ -9,7 +9,7 @@ assignees: ''
|
||||
|
||||
----
|
||||
|
||||
(Please try the latest nightly release before submitting this. You can find the latest nightly version here: https://github.com/eried/portapack-mayhem/releases)
|
||||
(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)
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ assignees: ''
|
||||
|
||||
----
|
||||
Before creating this issue, **do the following**:
|
||||
* Read the Wiki on booting: https://github.com/eried/portapack-mayhem/wiki/Won't-boot
|
||||
* Read: https://github.com/eried/portapack-havoc/wiki/Update-firmware
|
||||
* Read the Wiki on booting: https://github.com/portapack-mayhem/mayhem-firmware/wiki/Won't-boot
|
||||
* Read: https://github.com/portapack-mayhem/mayhem-firmware/wiki/Update-firmware
|
||||
* Watch carefully: https://www.youtube.com/watch?v=_zx4ZvurgOs
|
||||
* (if you are not in Windows) also check: https://www.youtube.com/watch?v=kjFB58Y1TAo
|
||||
|
||||
@@ -27,12 +27,12 @@ Steps to reproduce the behavior:
|
||||
|
||||
**My Hardware**
|
||||
Please specify what PortaPack hardware version you are using.
|
||||
You can find the list of versions here: https://github.com/eried/portapack-mayhem/wiki/PortaPack-Versions
|
||||
You can find the list of versions here: https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions
|
||||
|
||||
**Affected versions**
|
||||
Please tell us what version you are running.
|
||||
If your device is still functional, try the latest nightly release before submitting this.
|
||||
You can find the latest nightly version here https://github.com/eried/portapack-mayhem/releases
|
||||
You can find the latest nightly version here https://github.com/portapack-mayhem/mayhem-firmware/releases
|
||||
|
||||
**Were you able to update the firmware before?**
|
||||
Things might be confusing the first time, please check the video available on the link above.
|
||||
|
||||
@@ -6,8 +6,8 @@ from datetime import datetime, timedelta, timezone
|
||||
|
||||
# Set up your personal access token and the repository details
|
||||
token = os.environ.get('GH_TOKEN')
|
||||
repo_owner = "eried"
|
||||
repo_name = "portapack-mayhem"
|
||||
repo_owner = "portapack-mayhem"
|
||||
repo_name = "mayhem-firmware"
|
||||
|
||||
|
||||
def print_stable_changelog(previous_sha):
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version_date.outputs.date }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
- name: Download world map
|
||||
run: |
|
||||
wget https://github.com/eried/portapack-mayhem/releases/download/world_map/world_map.zip
|
||||
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
|
||||
- name: Unzip world map
|
||||
run: |
|
||||
unzip world_map.zip -d sdcard/ADSB
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
mkdir -p sdcard/FIRMWARE && cp build/firmware/portapack-h1_h2-mayhem.bin sdcard/FIRMWARE/portapack-mayhem_${{ steps.version.outputs.version }}.bin && mkdir -p sdcard/APPS && cp build/firmware/application/*.ppma sdcard/APPS && cd sdcard && zip -r ../sdcard-no-map.zip . && cd ..
|
||||
- name: Download world map
|
||||
run: |
|
||||
wget https://github.com/eried/portapack-mayhem/releases/download/world_map/world_map.zip
|
||||
wget https://github.com/portapack-mayhem/mayhem-firmware/releases/download/world_map/world_map.zip
|
||||
- name: Unzip world map
|
||||
run: |
|
||||
unzip world_map.zip -d sdcard/ADSB
|
||||
@@ -71,15 +71,15 @@ jobs:
|
||||
release_name: Mayhem firmware ${{ steps.version.outputs.version }}
|
||||
body: |
|
||||
**Stable release - ${{ steps.version.outputs.version }}**
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). Please check the [readme](https://github.com/eried/portapack-mayhem/blob/master/README.md) for details.
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). Please check the [readme](https://github.com/portapack-mayhem/mayhem-firmware/blob/master/README.md) for details.
|
||||
## Release notes
|
||||
### Revision (${{ steps.version.outputs.version }}):
|
||||
${{ steps.changelog.outputs.content }}
|
||||
|
||||
**Full Changelog**: https://github.com/eried/portapack-mayhem/compare/${{ steps.past_version.outputs.past_version }}...${{ steps.version.outputs.version }}
|
||||
**Full Changelog**: https://github.com/portapack-mayhem/mayhem-firmware/compare/${{ steps.past_version.outputs.past_version }}...${{ steps.version.outputs.version }}
|
||||
|
||||
## Installation
|
||||
Check the [wiki](https://github.com/eried/portapack-havoc/wiki/Update-firmware) for details how to upgrade.
|
||||
Check the [wiki](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Update-firmware) for details how to upgrade.
|
||||
__Warning:__ Since release 1.8.0, some applications has been moved to the SD card as we ran out of flash space.
|
||||
|
||||
### MicroSD card files
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
> [!IMPORTANT]
|
||||
> *Shortly*, this repository **will be moved** from my personal GitHub [eried/portapack-mayhem](https://github.com/eried/portapack-mayhem) to an organization: [portapack-mayhem](https://github.com/portapack-mayhem/). Please keep this in mind to **update your links** accordingly.
|
||||
> 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.
|
||||
|
||||
# PortaPack Mayhem
|
||||
|
||||
[](https://travis-ci.com/eried/portapack-mayhem) [](https://github.com/eried/portapack-mayhem/actions/workflows/create_nightly_release.yml) [](https://codescene.io/projects/8381) [](https://github.com/eried/portapack-mayhem/releases) [](https://github.com/eried/portapack-mayhem/releases/latest) [](https://hub.docker.com/r/eried/portapack) [](https://discord.gg/tuwVMv3)
|
||||
[](https://github.com/portapack-mayhem/mayhem-firmware/actions/workflows/create_nightly_release.yml) [](https://codescene.io/projects/8381) [](https://github.com/portapack-mayhem/mayhem-firmware/releases) [](https://github.com/portapack-mayhem/mayhem-firmware/releases/latest) [](https://hub.docker.com/r/eried/portapack) [](https://discord.gg/tuwVMv3)
|
||||
|
||||
This is a fork of the [Havoc](https://github.com/furrtek/portapack-havoc/) firmware, which itself was a fork of the [PortaPack](https://github.com/sharebrained/portapack-hackrf) firmware, an add-on for the [HackRF](http://greatscottgadgets.com/hackrf/). A fork is a derivate, in this case one that has extra features and fixes when compared to the older versions.
|
||||
|
||||
[<img src="https://raw.githubusercontent.com/wiki/eried/portapack-mayhem/img/hw_overview_h2_front.png" height="400">](https://github.com/eried/portapack-mayhem/wiki/Hardware-overview) [<img src="https://raw.githubusercontent.com/wiki/eried/portapack-mayhem/img/hw_overview_h2_inside.png" height="400">](https://github.com/eried/portapack-mayhem/wiki/Hardware-overview#portapack-internals)
|
||||
[<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_front.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview) [<img src="https://raw.githubusercontent.com/wiki/portapack-mayhem/mayhem-firmware/img/hw_overview_h2_inside.png" height="400">](https://github.com/portapack-mayhem/mayhem-firmware/wiki/Hardware-overview#portapack-internals)
|
||||
|
||||
*[PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_DmU7GQX) (clone) with a custom [3d printed case](https://github.com/eried/portapack-mayhem/wiki/H2-Enclosure)*
|
||||
*[PortaPack H2+HackRF+battery](https://s.click.aliexpress.com/e/_DmU7GQX) (clone) with a custom [3d printed case](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure)*
|
||||
|
||||
# What is this?
|
||||
|
||||
@@ -21,11 +21,11 @@ For people familiar with the [Flipper Zero](https://github.com/flipperdevices/fl
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
This repository expands upon the previous work by many people and aims to constantly add new features, bugfixes and generate documentation to make further development easier. [Collaboration](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate) is always welcomed and appreciated.
|
||||
This repository expands upon the previous work by many people and aims to constantly add new features, bugfixes and generate documentation to make further development easier. [Collaboration](https://github.com/portapack-mayhem/mayhem-firmware/wiki/How-to-collaborate) is always welcomed and appreciated.
|
||||
|
||||
## What to buy?
|
||||
|
||||
:heavy_check_mark: A recommended one is this [PortaPack H2](https://s.click.aliexpress.com/e/_DmU7GQX), that includes everything you need with the plastic case "inspired" on [this](https://github.com/eried/portapack-mayhem/wiki/H2-Enclosure).
|
||||
:heavy_check_mark: A recommended one is this [PortaPack H2](https://s.click.aliexpress.com/e/_DmU7GQX), that includes everything you need with the plastic case "inspired" on [this](https://github.com/portapack-mayhem/mayhem-firmware/wiki/H2-Enclosure).
|
||||
|
||||
:heavy_check_mark: Our friends at OpenSourceSDRLab give away five units every three months in our discord (check the badge on top) of their [PortaPack H2](https://www.aliexpress.com/item/4000247041639.html?gatewayAdapt=4itemAdapt), you can support them too by ordering.
|
||||
|
||||
@@ -35,33 +35,33 @@ This repository expands upon the previous work by many people and aims to consta
|
||||
|
||||

|
||||
|
||||
:warning: If it looks **too different**, this might mean that they are using their own recipe, check the [different models](https://github.com/eried/portapack-mayhem/wiki/PortaPack-Versions) in our wiki. For example all the H3 and clones of that version use their own version of the firmware. They do not contribute the changes back and eventually you will be left with a device that nobody maintains:
|
||||
:warning: If it looks **too different**, this might mean that they are using their own recipe, check the [different models](https://github.com/portapack-mayhem/mayhem-firmware/wiki/PortaPack-Versions) in our wiki. For example all the H3 and clones of that version use their own version of the firmware. They do not contribute the changes back and eventually you will be left with a device that nobody maintains:
|
||||
|
||||

|
||||
|
||||
## Where is the latest version?
|
||||
|
||||
The current **stable release** is on the [](https://github.com/eried/portapack-mayhem/releases/latest) page. Follow the instructions you can find in the release description. The **latest (nightly) release** can be found [here](https://github.com/eried/portapack-mayhem/releases/).
|
||||
The current **stable release** is on the [](https://github.com/portapack-mayhem/mayhem-firmware/releases/latest) page. Follow the instructions you can find in the release description. The **latest (nightly) release** can be found [here](https://github.com/portapack-mayhem/mayhem-firmware/releases/).
|
||||
|
||||
## How can I collaborate
|
||||
You can write [documentation](https://github.com/eried/portapack-mayhem/wiki), fix bugs and [answer issues](https://github.com/eried/portapack-mayhem/issues) or add new functionality. Please check the following [guide](https://github.com/eried/portapack-mayhem/wiki/How-to-collaborate) with details.
|
||||
You can write [documentation](https://github.com/portapack-mayhem/mayhem-firmware/wiki), fix bugs and [answer issues](https://github.com/portapack-mayhem/mayhem-firmware/issues) or add new functionality. Please check the following [guide](https://github.com/portapack-mayhem/mayhem-firmware/wiki/How-to-collaborate) with details.
|
||||
|
||||
Consider that the hardware and firmware has been created and maintain by a [lot](https://github.com/mossmann/hackrf/graphs/contributors) of [people](https://github.com/eried/portapack-mayhem/graphs/contributors), so always try collaborating your time and effort first. For coding related questions, if something does not fit as an issue, please join our Discord by clicking the chat badge on [top](#portapack-mayhem).
|
||||
Consider that the hardware and firmware has been created and maintain by a [lot](https://github.com/mossmann/hackrf/graphs/contributors) of [people](https://github.com/portapack-mayhem/mayhem-firmware/graphs/contributors), so always try collaborating your time and effort first. For coding related questions, if something does not fit as an issue, please join our Discord by clicking the chat badge on [top](#portapack-mayhem).
|
||||
|
||||
[](https://github.com/eried/portapack-mayhem/graphs/contributors)
|
||||
[](https://github.com/portapack-mayhem/mayhem-firmware/graphs/contributors)
|
||||
|
||||
To support the people behind the hardware, please buy a genuine [HackRF](https://greatscottgadgets.com/hackrf/) and [PortaPack](https://store.sharebrained.com/products/portapack-for-hackrf-one-kit).
|
||||
|
||||
## What if I really want something specific?
|
||||
If what you need can be relevant in general, you can [request a feature](https://github.com/eried/portapack-mayhem/issues/new?labels=enhancement&template=feature_request.md).
|
||||
If what you need can be relevant in general, you can [request a feature](https://github.com/portapack-mayhem/mayhem-firmware/issues/new?labels=enhancement&template=feature_request.md).
|
||||
|
||||
<del>You can create a bounty and invite people to your own bounty. This will incentivize coders to work on a new feature, solving a bug or even writting documentation. Start a bounty by [creating](https://github.com/eried/portapack-mayhem/issues/new/choose) or [choosing](https://github.com/eried/portapack-mayhem/issues/) an existing issue. Then, go to [Bountysource](https://www.bountysource.com/) and post a bounty using the link to that specific [issue](https://www.bountysource.com/teams/portapack-mayhem/issues).</del>
|
||||
<del>You can create a bounty and invite people to your own bounty. This will incentivize coders to work on a new feature, solving a bug or even writting documentation. Start a bounty by [creating](https://github.com/portapack-mayhem/mayhem-firmware/issues/new/choose) or [choosing](https://github.com/portapack-mayhem/mayhem-firmware/issues/) an existing issue. Then, go to [Bountysource](https://www.bountysource.com/) and post a bounty using the link to that specific [issue](https://www.bountysource.com/teams/portapack-mayhem/issues).</del>
|
||||
|
||||
<del>Promote your bounty over our Discord by clicking the chat badge on [top](#portapack-mayhem).</del>
|
||||
|
||||
Bountysource has not been reliable lately, so until this changes, please **DO NOT** post a bounty there. Go to our Discord by clicking the chat badge on [top](#portapack-mayhem) and discuss there.
|
||||
|
||||
## What if I need help?
|
||||
First, check the [documentation](https://github.com/eried/portapack-mayhem/wiki). If you find a bug or you think the problem is related to the current repository, please open an [issue](https://github.com/eried/portapack-mayhem/issues/new/choose).
|
||||
First, check the [documentation](https://github.com/portapack-mayhem/mayhem-firmware/wiki). If you find a bug or you think the problem is related to the current repository, please open an [issue](https://github.com/portapack-mayhem/mayhem-firmware/issues/new/choose).
|
||||
|
||||
You can reach the [official community](https://www.facebook.com/groups/177623356165819) in Facebook, and our Discord by clicking the chat badge on [top](#portapack-mayhem).
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=https://github.com/eried/portapack-mayhem/" />
|
||||
<meta http-equiv="refresh" content="0; URL=https://github.com/portapack-mayhem/mayhem-firmware/" />
|
||||
</head>
|
||||
<body>
|
||||
<p>If you are not redirected, <a href="https://github.com/eried/portapack-mayhem/">click here</a>.</p>
|
||||
<p>If you are not redirected, <a href="https://github.com/portapack-mayhem/mayhem-firmware/">click here</a>.</p>
|
||||
</body>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "string_format.hpp"
|
||||
#include "tonesets.hpp"
|
||||
#include "ui_tone_key.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
using namespace tonekey;
|
||||
using namespace portapack;
|
||||
@@ -40,6 +41,7 @@ void SoundBoardView::stop() {
|
||||
if (is_active())
|
||||
replay_thread.reset();
|
||||
|
||||
audio::output::stop();
|
||||
transmitter_model.disable();
|
||||
tx_view.set_transmitting(false);
|
||||
|
||||
@@ -123,6 +125,8 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
||||
transmitter_model.enable();
|
||||
|
||||
tx_view.set_transmitting(true);
|
||||
|
||||
audio::output::start();
|
||||
}
|
||||
|
||||
/*void SoundBoardView::show_infos() {
|
||||
@@ -227,6 +231,7 @@ SoundBoardView::SoundBoardView(
|
||||
//&text_title,
|
||||
//&text_duration,
|
||||
//&progressbar,
|
||||
&field_volume,
|
||||
&page_info,
|
||||
&check_loop,
|
||||
&check_random,
|
||||
@@ -274,7 +279,6 @@ SoundBoardView::SoundBoardView(
|
||||
|
||||
SoundBoardView::~SoundBoardView() {
|
||||
stop();
|
||||
transmitter_model.disable();
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class SoundBoardView : public View {
|
||||
void on_select_entry();
|
||||
|
||||
Labels labels{
|
||||
//{ { 0, 20 * 8 + 4 }, "Title:", Color::light_grey() },
|
||||
{{24 * 8, 180}, "Vol:", Color::light_grey()},
|
||||
{{0, 180}, "Key:", Color::light_grey()}};
|
||||
|
||||
Button button_next_page{
|
||||
@@ -122,10 +122,13 @@ class SoundBoardView : public View {
|
||||
};*/
|
||||
|
||||
OptionsField options_tone_key{
|
||||
{32, 180},
|
||||
{4 * 8, 180},
|
||||
18,
|
||||
{}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 180}};
|
||||
|
||||
Checkbox check_loop{
|
||||
{0, 25 * 8 + 4},
|
||||
4,
|
||||
|
||||
@@ -19,7 +19,7 @@ void AboutView::update() {
|
||||
switch (++frame) {
|
||||
case 1:
|
||||
// TODO: Generate this automatically from github
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?to=2022-01-01&from=2020-04-12&type=c
|
||||
// https://github.com/portapack-mayhem/mayhem-firmware/graphs/contributors?to=2022-01-01&from=2020-04-12&type=c
|
||||
console.writeln(STR_COLOR_DARK_YELLOW "Mayhem:");
|
||||
console.writeln("eried,euquiq,gregoryfenton");
|
||||
console.writeln("johnelder,jwetzell,nnemanjan00");
|
||||
@@ -42,7 +42,7 @@ void AboutView::update() {
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?to=2020-04-12&from=2015-07-31&type=c
|
||||
// https://github.com/portapack-mayhem/mayhem-firmware/graphs/contributors?to=2020-04-12&from=2015-07-31&type=c
|
||||
console.writeln(STR_COLOR_DARK_YELLOW "Havoc:");
|
||||
console.writeln("furrtek,mrmookie,NotPike");
|
||||
console.writeln("mjwaxios,ImDroided,Giorgiofox");
|
||||
@@ -55,7 +55,7 @@ void AboutView::update() {
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// https://github.com/eried/portapack-mayhem/graphs/contributors?from=2014-07-05&to=2015-07-31&type=c
|
||||
// https://github.com/portapack-mayhem/mayhem-firmware/graphs/contributors?from=2014-07-05&to=2015-07-31&type=c
|
||||
console.writeln(STR_COLOR_DARK_YELLOW "PortaPack:");
|
||||
console.writeln("jboone,argilo");
|
||||
console.writeln("");
|
||||
|
||||
@@ -318,6 +318,17 @@ bool ADSBRxDetailsView::add_map_marker(const AircraftRecentEntry& entry) {
|
||||
return markerStored == MARKER_STORED;
|
||||
}
|
||||
|
||||
void ADSBRxDetailsView::on_gps(const GPSPosDataMessage* msg) {
|
||||
if (!geomap_view_)
|
||||
return;
|
||||
geomap_view_->update_my_position(msg->lat, msg->lon, msg->altitude);
|
||||
}
|
||||
void ADSBRxDetailsView::on_orientation(const OrientationDataMessage* msg) {
|
||||
if (!geomap_view_)
|
||||
return;
|
||||
geomap_view_->update_my_orientation(msg->angle);
|
||||
}
|
||||
|
||||
void ADSBRxDetailsView::refresh_ui() {
|
||||
auto age = entry_.age;
|
||||
if (age < 60)
|
||||
|
||||
@@ -271,6 +271,8 @@ class ADSBRxDetailsView : public View {
|
||||
|
||||
private:
|
||||
void refresh_ui();
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
|
||||
GeoMapView* geomap_view_{nullptr};
|
||||
ADSBRxAircraftDetailsView* aircraft_details_view_{nullptr};
|
||||
@@ -330,6 +332,19 @@ class ADSBRxDetailsView : public View {
|
||||
Button button_see_map{
|
||||
{16 * 8, 9 * 16, 12 * 8, 3 * 16},
|
||||
"See on map"};
|
||||
|
||||
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);
|
||||
}};
|
||||
};
|
||||
|
||||
/* Main ADSB application view and message dispatch. */
|
||||
|
||||
@@ -275,7 +275,7 @@ ScannerView::~ScannerView() {
|
||||
}
|
||||
|
||||
void ScannerView::show_max_index() { // show total number of freqs to scan
|
||||
field_current_index.set_text("---");
|
||||
field_current_index.set_text("<->");
|
||||
|
||||
if (entries.size() == FREQMAN_MAX_PER_FILE) {
|
||||
text_max_index.set_style(&Styles::red);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_touch_calibration.hpp"
|
||||
#include "ui_text_editor.hpp"
|
||||
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "lpc43xx_cpp.hpp"
|
||||
@@ -628,6 +629,34 @@ void SetEncoderDialView::focus() {
|
||||
button_save.focus();
|
||||
}
|
||||
|
||||
/* AppSettingsView ************************************/
|
||||
|
||||
AppSettingsView::AppSettingsView(
|
||||
NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children({&labels,
|
||||
&menu_view});
|
||||
|
||||
menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8});
|
||||
|
||||
ensure_directory(SETTINGS_DIR);
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(SETTINGS_DIR, u"*.ini")) {
|
||||
auto path = (std::filesystem::path)SETTINGS_DIR / entry.path();
|
||||
|
||||
menu_view.add_item({path.filename().string().substr(0, 26),
|
||||
ui::Color::dark_cyan(),
|
||||
&bitmap_icon_file_text,
|
||||
[this, path](KeyEvent) {
|
||||
nav_.push<TextEditorView>(path);
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
void AppSettingsView::focus() {
|
||||
menu_view.focus();
|
||||
}
|
||||
|
||||
/* SettingsMenuView **************************************/
|
||||
|
||||
SettingsMenuView::SettingsMenuView(NavigationView& nav) {
|
||||
@@ -635,6 +664,7 @@ SettingsMenuView::SettingsMenuView(NavigationView& nav) {
|
||||
add_items({{"..", ui::Color::light_grey(), &bitmap_icon_previous, [&nav]() { nav.pop(); }}});
|
||||
}
|
||||
add_items({
|
||||
{"App Settings", ui::Color::dark_cyan(), &bitmap_icon_notepad, [&nav]() { nav.push<AppSettingsView>(); }},
|
||||
{"Audio", ui::Color::dark_cyan(), &bitmap_icon_speaker, [&nav]() { nav.push<SetAudioView>(); }},
|
||||
{"Calibration", ui::Color::dark_cyan(), &bitmap_icon_options_touch, [&nav]() { nav.push<TouchCalibrationView>(); }},
|
||||
{"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push<SetConverterSettingsView>(); }},
|
||||
|
||||
@@ -564,6 +564,23 @@ class SetPersistentMemoryView : public View {
|
||||
};
|
||||
};
|
||||
|
||||
class AppSettingsView : public View {
|
||||
public:
|
||||
AppSettingsView(NavigationView& nav);
|
||||
std::string title() const override { return "App Settings"; };
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
|
||||
Labels labels{
|
||||
{{0, 4}, "Select file to edit:", Color::white()}};
|
||||
|
||||
MenuView menu_view{
|
||||
{0, 2 * 8, 240, 26 * 8},
|
||||
true};
|
||||
};
|
||||
|
||||
class SettingsMenuView : public BtnGridView {
|
||||
public:
|
||||
SettingsMenuView(NavigationView& nav);
|
||||
|
||||
@@ -90,7 +90,7 @@ SondeView::SondeView(NavigationView& nav)
|
||||
};
|
||||
|
||||
button_see_map.on_select = [this, &nav](Button&) {
|
||||
nav.push<GeoMapView>(
|
||||
geomap_view_ = nav.push<GeoMapView>(
|
||||
sonde_id,
|
||||
gps_info.alt,
|
||||
GeoPos::alt_unit::METERS,
|
||||
@@ -98,6 +98,9 @@ SondeView::SondeView(NavigationView& nav)
|
||||
gps_info.lat,
|
||||
gps_info.lon,
|
||||
999); // set a dummy heading out of range to draw a cross...probably not ideal?
|
||||
nav.set_on_pop([this]() {
|
||||
geomap_view_ = nullptr;
|
||||
});
|
||||
};
|
||||
|
||||
logger = std::make_unique<SondeLogger>();
|
||||
@@ -124,6 +127,17 @@ SondeView::~SondeView() {
|
||||
audio::output::stop();
|
||||
}
|
||||
|
||||
void SondeView::on_gps(const GPSPosDataMessage* msg) {
|
||||
if (!geomap_view_)
|
||||
return;
|
||||
geomap_view_->update_my_position(msg->lat, msg->lon, msg->altitude);
|
||||
}
|
||||
void SondeView::on_orientation(const OrientationDataMessage* msg) {
|
||||
if (!geomap_view_)
|
||||
return;
|
||||
geomap_view_->update_my_orientation(msg->angle, true);
|
||||
}
|
||||
|
||||
void SondeView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ class SondeView : public View {
|
||||
|
||||
SondeView(NavigationView& nav);
|
||||
~SondeView();
|
||||
SondeView(const SondeView& other) = delete;
|
||||
SondeView& operator=(const SondeView& other) = delete;
|
||||
|
||||
void focus() override;
|
||||
|
||||
@@ -173,6 +175,8 @@ class SondeView : public View {
|
||||
{16 * 8, 15 * 16, 12 * 8, 3 * 16},
|
||||
"See on map"};
|
||||
|
||||
GeoMapView* geomap_view_{nullptr};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::SondePacket,
|
||||
[this](Message* const p) {
|
||||
@@ -181,6 +185,21 @@ class SondeView : public View {
|
||||
this->on_packet(packet);
|
||||
}};
|
||||
|
||||
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);
|
||||
}};
|
||||
|
||||
void on_gps(const GPSPosDataMessage* msg);
|
||||
void on_orientation(const OrientationDataMessage* msg);
|
||||
void on_packet(const sonde::Packet& packet);
|
||||
char* float_to_char(float x, char* p);
|
||||
};
|
||||
|
||||
@@ -410,6 +410,9 @@ void EventDispatcher::handle_encoder() {
|
||||
|
||||
const uint32_t encoder_now = get_encoder_position();
|
||||
const int32_t delta = static_cast<int32_t>(encoder_now - encoder_last);
|
||||
if (delta == 0)
|
||||
return;
|
||||
|
||||
encoder_last = encoder_now;
|
||||
const auto event = static_cast<ui::EncoderEvent>(delta);
|
||||
event_bubble_encoder(event);
|
||||
|
||||
@@ -305,6 +305,7 @@ void GeoMap::paint(Painter& painter) {
|
||||
// Draw the other markers
|
||||
draw_markers(painter);
|
||||
draw_scale(painter);
|
||||
draw_mypos();
|
||||
markerListUpdated = false;
|
||||
set_clean();
|
||||
}
|
||||
@@ -447,6 +448,41 @@ void GeoMap::draw_marker(Painter& painter, const ui::Point itemPoint, const uint
|
||||
}
|
||||
}
|
||||
|
||||
void GeoMap::draw_mypos() {
|
||||
const auto r = screen_rect();
|
||||
if (my_lat >= 200 || my_lon >= 200) return; // invalid
|
||||
int x = (map_width * (my_lon + 180) / 360) - x_pos;
|
||||
double lat_rad = sin(my_lat * pi / 180);
|
||||
int y = (map_height - ((map_world_lon / 2 * log((1 + lat_rad) / (1 - lat_rad))) - map_offset)) - y_pos; // Offset added for the GUI
|
||||
auto color = Color::yellow();
|
||||
|
||||
if (map_zoom > 1) {
|
||||
x = ((x - (r.width() / 2)) * map_zoom) + (r.width() / 2);
|
||||
y = ((y - (r.height() / 2)) * map_zoom) + (r.height() / 2);
|
||||
} else if (map_zoom < 0) {
|
||||
x = ((x - (r.width() / 2)) / (-map_zoom)) + (r.width() / 2);
|
||||
y = ((y - (r.height() / 2)) / (-map_zoom)) + (r.height() / 2);
|
||||
}
|
||||
|
||||
if ((x >= 0) && (x < r.width()) &&
|
||||
(y > 10) && (y < r.height())) // Dont draw within symbol size of top
|
||||
{
|
||||
ui::Point itemPoint(x, y + r.top());
|
||||
if (mode_ == PROMPT) {
|
||||
// Cross
|
||||
display.fill_rectangle({itemPoint - Point(16, 1), {32, 2}}, color);
|
||||
display.fill_rectangle({itemPoint - Point(1, 16), {2, 32}}, color);
|
||||
} else if (my_angle < 360) {
|
||||
// if we have a valid angle draw bearing
|
||||
draw_bearing(itemPoint, my_angle, 10, color);
|
||||
} else {
|
||||
// draw a small cross
|
||||
display.fill_rectangle({itemPoint - Point(8, 1), {16, 2}}, color);
|
||||
display.fill_rectangle({itemPoint - Point(1, 8), {2, 16}}, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeoMap::clear_markers() {
|
||||
markerListLen = 0;
|
||||
}
|
||||
@@ -473,6 +509,21 @@ MapMarkerStored GeoMap::store_marker(GeoMarker& marker) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GeoMap::update_my_position(float lat, float lon, int32_t altitude) {
|
||||
my_lat = lat;
|
||||
my_lon = lon;
|
||||
my_altitude = altitude;
|
||||
markerListUpdated = true;
|
||||
set_dirty();
|
||||
}
|
||||
void GeoMap::update_my_orientation(uint16_t angle, bool refresh) {
|
||||
my_angle = angle;
|
||||
if (refresh) {
|
||||
markerListUpdated = true;
|
||||
set_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void GeoMapView::focus() {
|
||||
geopos.focus();
|
||||
|
||||
@@ -480,6 +531,13 @@ void GeoMapView::focus() {
|
||||
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT);
|
||||
}
|
||||
|
||||
void GeoMapView::update_my_position(float lat, float lon, int32_t altitude) {
|
||||
geomap.update_my_position(lat, lon, altitude);
|
||||
}
|
||||
void GeoMapView::update_my_orientation(uint16_t angle, bool refresh) {
|
||||
geomap.update_my_orientation(angle, refresh);
|
||||
}
|
||||
|
||||
void GeoMapView::update_position(float lat, float lon, uint16_t angle, int32_t altitude, int32_t speed) {
|
||||
if (geomap.manual_panning()) {
|
||||
geomap.set_dirty();
|
||||
|
||||
@@ -185,6 +185,9 @@ class GeoMap : public Widget {
|
||||
bool on_encoder(const EncoderEvent delta) override;
|
||||
bool on_keyboard(const KeyboardEvent event) override;
|
||||
|
||||
void update_my_position(float lat, float lon, int32_t altitude);
|
||||
void update_my_orientation(uint16_t angle, bool refresh = false);
|
||||
|
||||
bool init();
|
||||
void set_mode(GeoMapMode mode);
|
||||
void set_manual_panning(bool v);
|
||||
@@ -212,6 +215,7 @@ class GeoMap : public Widget {
|
||||
void draw_bearing(const Point origin, const uint16_t angle, uint32_t size, const Color color);
|
||||
void draw_marker(Painter& painter, const ui::Point itemPoint, const uint16_t itemAngle, const std::string itemTag, const Color color = Color::red(), const Color fontColor = Color::white(), const Color backColor = Color::black());
|
||||
void draw_markers(Painter& painter);
|
||||
void draw_mypos();
|
||||
void map_read_line(ui::Color* buffer, uint16_t pixels);
|
||||
|
||||
bool manual_panning_{false};
|
||||
@@ -233,6 +237,12 @@ class GeoMap : public Widget {
|
||||
uint16_t angle_{};
|
||||
std::string tag_{};
|
||||
|
||||
// the portapack's position data ( for example injected from serial )
|
||||
float my_lat{200};
|
||||
float my_lon{200};
|
||||
int32_t my_altitude{0};
|
||||
uint16_t my_angle{400};
|
||||
|
||||
int markerListLen{0};
|
||||
GeoMarker markerList[NumMarkerListElements];
|
||||
bool markerListUpdated{false};
|
||||
@@ -267,6 +277,8 @@ class GeoMapView : public View {
|
||||
void focus() override;
|
||||
|
||||
void update_position(float lat, float lon, uint16_t angle, int32_t altitude, int32_t speed = 0);
|
||||
void update_my_position(float lat, float lon, int32_t altitude);
|
||||
void update_my_orientation(uint16_t angle, bool refresh = false);
|
||||
|
||||
std::string title() const override { return "Map view"; };
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ std::vector<AppInfoConsole> NavigationView::fixedAppListFC = {
|
||||
{"lookingglass", "Looking Glass", RX}};
|
||||
|
||||
bool NavigationView::StartAppByName(const char* name) {
|
||||
pop();
|
||||
home(false);
|
||||
if (strcmp(name, "adsbrx") == 0) {
|
||||
push<ADSBRxView>();
|
||||
return true;
|
||||
@@ -660,6 +660,14 @@ void NavigationView::pop(bool trigger_update) {
|
||||
if (on_pop) on_pop();
|
||||
}
|
||||
|
||||
void NavigationView::home(bool trigger_update) {
|
||||
while (view_stack.size() > 1) {
|
||||
pop(false);
|
||||
}
|
||||
|
||||
if (trigger_update) update_view();
|
||||
}
|
||||
|
||||
void NavigationView::display_modal(
|
||||
const std::string& title,
|
||||
const std::string& message) {
|
||||
|
||||
@@ -91,6 +91,7 @@ class NavigationView : public View {
|
||||
View* push_view(std::unique_ptr<View> new_view);
|
||||
void replace(View* v);
|
||||
void pop(bool trigger_update = true);
|
||||
void home(bool trigger_update);
|
||||
|
||||
void display_modal(const std::string& title, const std::string& message);
|
||||
void display_modal(
|
||||
|
||||
@@ -40,13 +40,19 @@
|
||||
|
||||
SerialUSBDriver SUSBD1;
|
||||
|
||||
uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE];
|
||||
|
||||
void bulk_out_receive(void) {
|
||||
int ret;
|
||||
|
||||
while (chIQGetEmptyI(&SUSBD1.iqueue) < USB_BULK_BUFFER_SIZE)
|
||||
chThdSleepMilliseconds(1); // wait for shell thread when buffer is full
|
||||
|
||||
do {
|
||||
ret = usb_transfer_schedule(
|
||||
&usb_endpoint_bulk_out,
|
||||
&usb_endpoint_bulk_out.buffer[0],
|
||||
32,
|
||||
&usb_bulk_buffer[0],
|
||||
USB_BULK_BUFFER_SIZE,
|
||||
serial_bulk_transfer_complete,
|
||||
NULL);
|
||||
|
||||
@@ -57,25 +63,25 @@ void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferr
|
||||
(void)user_data;
|
||||
|
||||
chSysLockFromIsr();
|
||||
|
||||
for (unsigned int i = 0; i < bytes_transferred; i++) {
|
||||
msg_t ret;
|
||||
do {
|
||||
ret = chIQPutI(&SUSBD1.iqueue, usb_endpoint_bulk_out.buffer[i]);
|
||||
if (ret == Q_FULL)
|
||||
chThdSleepMilliseconds(1);
|
||||
ret = chIQPutI(&SUSBD1.iqueue, usb_bulk_buffer[i]);
|
||||
|
||||
if (ret == Q_FULL) {
|
||||
chDbgPanic("USB iqueue buffer full");
|
||||
}
|
||||
|
||||
} while (ret == Q_FULL);
|
||||
}
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
|
||||
static void onotify(GenericQueue* qp) {
|
||||
SerialUSBDriver* sdp = chQGetLink(qp);
|
||||
uint8_t buff[64];
|
||||
uint8_t buff[USBSERIAL_BUFFERS_SIZE];
|
||||
int n = chOQGetFullI(&sdp->oqueue);
|
||||
if (n > 64) n = 64; // don't overflow
|
||||
if (n > USBSERIAL_BUFFERS_SIZE) n = USBSERIAL_BUFFERS_SIZE; // don't overflow
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
buff[i] = chOQGetI(&sdp->oqueue);
|
||||
@@ -139,8 +145,8 @@ static const struct SerialUSBDriverVMT vmt = {
|
||||
|
||||
void init_serial_usb_driver(SerialUSBDriver* sdp) {
|
||||
sdp->vmt = &vmt;
|
||||
chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, NULL, sdp);
|
||||
chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp);
|
||||
chIQInit(&sdp->iqueue, sdp->ib, USBSERIAL_BUFFERS_SIZE, NULL, sdp);
|
||||
chOQInit(&sdp->oqueue, sdp->ob, USBSERIAL_BUFFERS_SIZE, onotify, sdp);
|
||||
}
|
||||
|
||||
// queue handler from ch
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#define USB_BULK_BUFFER_SIZE 64
|
||||
|
||||
#ifndef USBSERIAL_BUFFERS_SIZE
|
||||
#define USBSERIAL_BUFFERS_SIZE 128
|
||||
#endif
|
||||
|
||||
struct SerialUSBDriverVMT {
|
||||
_base_asynchronous_channel_methods
|
||||
};
|
||||
@@ -31,10 +37,10 @@ struct SerialUSBDriverVMT {
|
||||
struct SerialUSBDriver {
|
||||
/** @brief Virtual Methods Table.*/
|
||||
const struct SerialUSBDriverVMT* vmt;
|
||||
InputQueue iqueue; /* Output queue.*/
|
||||
OutputQueue oqueue; /* Input circular buffer.*/
|
||||
uint8_t ib[SERIAL_BUFFERS_SIZE]; /* Output circular buffer.*/
|
||||
uint8_t ob[SERIAL_BUFFERS_SIZE];
|
||||
InputQueue iqueue; /* Output queue.*/
|
||||
OutputQueue oqueue; /* Input circular buffer.*/
|
||||
uint8_t ib[USBSERIAL_BUFFERS_SIZE]; /* Output circular buffer.*/
|
||||
uint8_t ob[USBSERIAL_BUFFERS_SIZE];
|
||||
};
|
||||
|
||||
typedef struct SerialUSBDriver SerialUSBDriver;
|
||||
|
||||
@@ -142,6 +142,13 @@ static void cmd_flash(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto evtd = getEventDispatcherInstance();
|
||||
if (!evtd) return;
|
||||
auto top_widget = evtd->getTopWidget();
|
||||
if (!top_widget) return;
|
||||
auto nav = static_cast<ui::SystemView*>(top_widget)->get_navigation_view();
|
||||
if (!nav) return;
|
||||
nav->display_modal("Flashing", "Flashing from serial.\rPlease wait!\nDevice will restart.");
|
||||
// check file extensions
|
||||
if (strEndsWith(path.native(), u".ppfw.tar")) {
|
||||
// extract tar
|
||||
@@ -153,6 +160,7 @@ static void cmd_flash(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
});
|
||||
if (res.empty()) {
|
||||
chprintf(chp, "error bad TAR file.\r\n");
|
||||
nav->pop();
|
||||
return;
|
||||
}
|
||||
path = res; // it will contain the last bin file in tar
|
||||
@@ -160,8 +168,10 @@ static void cmd_flash(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
// nothing to do for this case yet.
|
||||
} else {
|
||||
chprintf(chp, "error only .bin or .ppfw.tar files canbe flashed.\r\n");
|
||||
nav->pop();
|
||||
return;
|
||||
}
|
||||
|
||||
chprintf(chp, "Flashing: ");
|
||||
chprintf(chp, path.string().c_str());
|
||||
chprintf(chp, "\r\n");
|
||||
@@ -241,18 +251,17 @@ static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv
|
||||
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);
|
||||
for (int px = 0; px < ui::screen_width; px += 60) {
|
||||
char buffer[60];
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
buffer[i] = getChrFromRgb(row[px + i].r, row[px + i].g, row[px + i].b);
|
||||
}
|
||||
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 60);
|
||||
char buffer[242];
|
||||
for (int i = 0; i < 240; ++i) {
|
||||
buffer[i] = getChrFromRgb(row[i].r, row[i].g, row[i].b);
|
||||
}
|
||||
chprintf(chp, "\r\n");
|
||||
buffer[240] = '\r';
|
||||
buffer[241] = '\n';
|
||||
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 242);
|
||||
}
|
||||
|
||||
evtd->exit_shell_working_mode();
|
||||
chprintf(chp, "ok\r\n");
|
||||
chprintf(chp, "\r\nok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_write_memory(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
@@ -878,6 +887,35 @@ static void cmd_cpld_read(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_gotgps(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
const char* usage = "usage: gotgps <lat> <lon> [altitude] [speed]\r\n";
|
||||
if (argc < 2 || argc > 4) {
|
||||
chprintf(chp, usage);
|
||||
return;
|
||||
}
|
||||
float lat = atof(argv[0]);
|
||||
float lon = atof(argv[1]);
|
||||
int32_t altitude = 0;
|
||||
int32_t speed = 0;
|
||||
if (argc >= 3) altitude = strtol(argv[2], NULL, 10);
|
||||
if (argc >= 4) speed = strtol(argv[3], NULL, 10);
|
||||
GPSPosDataMessage msg{lat, lon, altitude, speed};
|
||||
EventDispatcher::send_message(msg);
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_gotorientation(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
const char* usage = "usage: gotorientation <angle>\r\n";
|
||||
if (argc != 1) {
|
||||
chprintf(chp, usage);
|
||||
return;
|
||||
}
|
||||
uint16_t angle = strtol(argv[0], NULL, 10);
|
||||
OrientationDataMessage msg{angle};
|
||||
EventDispatcher::send_message(msg);
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static const ShellCommand commands[] = {
|
||||
{"reboot", cmd_reboot},
|
||||
{"dfu", cmd_dfu},
|
||||
@@ -901,6 +939,8 @@ static const ShellCommand commands[] = {
|
||||
{"accessibility_readcurr", cmd_accessibility_readcurr},
|
||||
{"applist", cmd_applist},
|
||||
{"appstart", cmd_appstart},
|
||||
{"gotgps", cmd_gotgps},
|
||||
{"gotorientation", cmd_gotorientation},
|
||||
{NULL, NULL}};
|
||||
|
||||
static const ShellConfig shell_cfg1 = {
|
||||
|
||||
@@ -348,19 +348,23 @@ void cmd_sd_write_binary(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
long size = (int)strtol(argv[0], NULL, 10);
|
||||
size_t size = (size_t)strtol(argv[0], NULL, 10);
|
||||
|
||||
chprintf(chp, "send %d bytes\r\n", size);
|
||||
|
||||
uint8_t buffer;
|
||||
uint8_t buffer[USB_BULK_BUFFER_SIZE];
|
||||
|
||||
for (long i = 0; i < size; i++) {
|
||||
if (chSequentialStreamRead(chp, &buffer, 1) == 0)
|
||||
do {
|
||||
size_t bytes_to_read = size > USB_BULK_BUFFER_SIZE ? USB_BULK_BUFFER_SIZE : size;
|
||||
size_t bytes_read = chSequentialStreamRead(chp, &buffer[0], bytes_to_read);
|
||||
if (bytes_read != bytes_to_read)
|
||||
return;
|
||||
|
||||
auto error = shell_file->write(&buffer, 1);
|
||||
auto error = shell_file->write(&buffer[0], bytes_read);
|
||||
if (report_on_error(chp, error)) return;
|
||||
}
|
||||
|
||||
size -= bytes_read;
|
||||
} while (size > 0);
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
@@ -123,10 +123,10 @@ constexpr gpdma::channel::Config config_rx() {
|
||||
/* TODO: Clean up terminology around "buffer", "transfer", "samples" */
|
||||
|
||||
constexpr size_t buffer_samples_log2n = 7;
|
||||
constexpr size_t buffer_samples = (1 << buffer_samples_log2n);
|
||||
constexpr size_t buffer_samples = (1 << buffer_samples_log2n); // 2^7 = 128 byte circular DMA buffer
|
||||
constexpr size_t transfers_per_buffer_log2n = 2;
|
||||
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n);
|
||||
constexpr size_t transfer_samples = buffer_samples / transfers_per_buffer;
|
||||
constexpr size_t transfers_per_buffer = (1 << transfers_per_buffer_log2n); // 2^2 = 4 transfer buffers in the circular buffer
|
||||
constexpr size_t transfer_samples = buffer_samples / transfers_per_buffer; // 128/4 = 32 samples in each transfer buffer
|
||||
constexpr size_t transfers_mask = transfers_per_buffer - 1;
|
||||
|
||||
constexpr size_t buffer_bytes = buffer_samples * sizeof(sample_t);
|
||||
@@ -144,6 +144,8 @@ static constexpr auto& gpdma_channel_i2s0_rx = gpdma::channels[portapack::i2s0_r
|
||||
static volatile const gpdma::channel::LLI* tx_next_lli = nullptr;
|
||||
static volatile const gpdma::channel::LLI* rx_next_lli = nullptr;
|
||||
|
||||
static bool single_tx_buffer = false;
|
||||
|
||||
static void tx_transfer_complete() {
|
||||
tx_next_lli = gpdma_channel_i2s0_tx.next_lli();
|
||||
}
|
||||
@@ -213,11 +215,16 @@ void disable() {
|
||||
gpdma_channel_i2s0_rx.disable();
|
||||
}
|
||||
|
||||
void shrink_tx_buffer() {
|
||||
single_tx_buffer = true;
|
||||
lli_tx_loop[0].lli = lli_pointer(&lli_tx_loop[0]);
|
||||
}
|
||||
|
||||
buffer_t tx_empty_buffer() {
|
||||
const auto next_lli = tx_next_lli;
|
||||
if (next_lli) {
|
||||
const size_t next_index = next_lli - &lli_tx_loop[0];
|
||||
const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask;
|
||||
const size_t free_index = (single_tx_buffer) ? 0 : (next_index + transfers_per_buffer - 2) & transfers_mask;
|
||||
return {reinterpret_cast<sample_t*>(lli_tx_loop[free_index].srcaddr), transfer_samples};
|
||||
} else {
|
||||
return {nullptr, 0};
|
||||
|
||||
@@ -47,6 +47,7 @@ void init();
|
||||
void configure();
|
||||
void enable();
|
||||
void disable();
|
||||
void shrink_tx_buffer();
|
||||
|
||||
audio::buffer_t tx_empty_buffer();
|
||||
audio::buffer_t rx_empty_buffer();
|
||||
|
||||
@@ -41,6 +41,12 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Output to speaker too
|
||||
uint32_t imod32 = i & (AUDIO_OUTPUT_BUFFER_SIZE - 1);
|
||||
audio_data[imod32] = ((int16_t)audio_sample - 0x80) * (1.0f / 128.0f);
|
||||
if (imod32 == (AUDIO_OUTPUT_BUFFER_SIZE - 1))
|
||||
audio_output.write(audio_buffer);
|
||||
|
||||
sample = tone_gen.process(audio_sample - 0x80);
|
||||
|
||||
// FM
|
||||
@@ -95,6 +101,8 @@ void AudioTXProcessor::audio_config(const AudioTXConfigMessage& message) {
|
||||
tone_gen.configure(message.tone_key_delta, message.tone_key_mix_weight);
|
||||
progress_interval_samples = message.divider;
|
||||
resample_acc = 0;
|
||||
audio_output.configure(false);
|
||||
audio::dma::shrink_tx_buffer();
|
||||
}
|
||||
|
||||
void AudioTXProcessor::replay_config(const ReplayConfigMessage& message) {
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include "baseband_thread.hpp"
|
||||
#include "tone_gen.hpp"
|
||||
#include "stream_output.hpp"
|
||||
#include "audio_output.hpp"
|
||||
#include "audio_dma.hpp"
|
||||
|
||||
#define AUDIO_OUTPUT_BUFFER_SIZE 32
|
||||
|
||||
class AudioTXProcessor : public BasebandProcessor {
|
||||
public:
|
||||
@@ -48,6 +52,10 @@ class AudioTXProcessor : public BasebandProcessor {
|
||||
int32_t sample{0}, delta{};
|
||||
int8_t re{0}, im{0};
|
||||
|
||||
float audio_data[AUDIO_OUTPUT_BUFFER_SIZE];
|
||||
buffer_f32_t audio_buffer{audio_data, AUDIO_OUTPUT_BUFFER_SIZE, 48000};
|
||||
AudioOutput audio_output{};
|
||||
|
||||
size_t progress_interval_samples = 0, progress_samples = 0;
|
||||
|
||||
bool configured{false};
|
||||
|
||||
@@ -118,6 +118,8 @@ class Message {
|
||||
SubGhzFPRxConfigure = 60,
|
||||
WeatherData = 61,
|
||||
SubGhzDData = 62,
|
||||
GPSPosData = 63,
|
||||
OrientationData = 64,
|
||||
MAX
|
||||
};
|
||||
|
||||
@@ -1301,4 +1303,33 @@ class SubGhzDDataMessage : public Message {
|
||||
uint64_t data = 0;
|
||||
};
|
||||
|
||||
class GPSPosDataMessage : public Message {
|
||||
public:
|
||||
constexpr GPSPosDataMessage(
|
||||
float lat = 200.0,
|
||||
float lon = 200.0,
|
||||
int32_t altitude = 0,
|
||||
int32_t speed = 0)
|
||||
: Message{ID::GPSPosData},
|
||||
lat{lat},
|
||||
lon{lon},
|
||||
altitude{altitude},
|
||||
speed{speed} {
|
||||
}
|
||||
float lat = 200.0;
|
||||
float lon = 200.0;
|
||||
int32_t altitude = 0;
|
||||
int32_t speed = 0;
|
||||
};
|
||||
|
||||
class OrientationDataMessage : public Message {
|
||||
public:
|
||||
constexpr OrientationDataMessage(
|
||||
uint16_t angle = 400)
|
||||
: Message{ID::OrientationData},
|
||||
angle{angle} {
|
||||
}
|
||||
uint16_t angle = 400; //>360 -> no orientation set
|
||||
};
|
||||
|
||||
#endif /*__MESSAGE_H__*/
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/eried/portapack-mayhem/releases
|
||||
URL=https://github.com/portapack-mayhem/mayhem-firmware/releases
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/eried/portapack-mayhem/wiki/Update-firmware
|
||||
URL=https://github.com/portapack-mayhem/mayhem-firmware/wiki/Update-firmware
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
Plug HackRF+Portapack, set it in HackRF mode, launch flash_portapack_mayhem.bat
|
||||
|
||||
Read https://github.com/eried/portapack-mayhem/wiki/Update-firmware for more detailed information
|
||||
Read https://github.com/portapack-mayhem/mayhem-firmware/wiki/Update-firmware for more detailed information
|
||||
@@ -15,7 +15,7 @@ REM Check if the firmware file exists
|
||||
if not exist portapack-h1_h2-mayhem.bin (
|
||||
echo The firmware file "portapack-h1_h2-mayhem.bin" does not exist.
|
||||
echo Please ensure that you have downloaded the latest release from:
|
||||
echo https://github.com/eried/portapack-mayhem/releases/
|
||||
echo https://github.com/portapack-mayhem/mayhem-firmware/releases/
|
||||
echo.
|
||||
pause
|
||||
exit /b
|
||||
@@ -23,6 +23,6 @@ if not exist portapack-h1_h2-mayhem.bin (
|
||||
|
||||
"utils/hackrf_update.exe" portapack-h1_h2-mayhem.bin
|
||||
echo.
|
||||
echo If your device never boot after flashing, please refer to https://github.com/eried/portapack-mayhem/wiki/Won't-boot
|
||||
echo If your device never boot after flashing, please refer to https://github.com/portapack-mayhem/mayhem-firmware/wiki/Won't-boot
|
||||
echo.
|
||||
pause
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/eried/portapack-havoc/wiki/GPS-Sim
|
||||
URL=https://github.com/portapack-mayhem/mayhem-firmware/wiki/GPS-Sim
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Sample files below can be used with Replay app.
|
||||
|
||||
See [Wiki](https://github.com/eried/portapack-mayhem/wiki/C16-format) for more info over C16 file format.
|
||||
See [Wiki](https://github.com/portapack-mayhem/mayhem-firmware/wiki/C16-format) for more info over C16 file format.
|
||||
|
||||
| file | description | frequency |
|
||||
| ------ | ------ | ------: |
|
||||
|
||||
@@ -8,8 +8,8 @@ for the current splash screen to appear at power up, the "Show splash screen" op
|
||||
must also be enabled under Settings->UserInterface.
|
||||
|
||||
For more information on Splash Screens, see the following Wiki pages:
|
||||
https://github.com/eried/portapack-mayhem/wiki/Create-a-custom-splash-screen
|
||||
https://github.com/eried/portapack-mayhem/wiki/File-manager
|
||||
https://github.com/portapack-mayhem/mayhem-firmware/wiki/Create-a-custom-splash-screen
|
||||
https://github.com/portapack-mayhem/mayhem-firmware/wiki/File-manager
|
||||
|
||||
Many additional Mayhem splash screens that users have shared online may be found in
|
||||
the Mayhem #splash-screens channel on Discord.
|
||||
|
||||
Reference in New Issue
Block a user